퇴근5분전

/*
declare @i int = 1111111111111111111111111111
메시지 8115, 수준 16, 상태 2, 줄 2
expression을(를) 데이터 형식 int(으)로 변환하는 중 산술 오버플로 오류가 발생했습니다.
*/
 

/*
select CONVERT( varchar(10),
'aaaaaaaaaaaaaaaa' )
'aaaaaaaaaa' -- 결과
*/


/*
 declare @v table
 (
  valuedata varchar(4)
 )

 insert into @v values (  '2132132132132132321' )
 메시지 8152, 수준 16, 상태 14, 줄 8
 문자열이나 이진 데이터는 잘립니다.

*/

/*
 declare @v INT = '본사'  -- 메시지 245, 수준 16, 상태 1, 줄 3
 varchar 값 '본사'을(를) 데이터 형식 int(으)로 변환하지 못했습니다.
*/




SELECT a, b, c FROM (
VALUES
('C', 1, 'H' ) ,
('C', 2, 'I' ),
('C', 3, 'H' ),
('B', 2, 'H' ),
('B', 3, 'H' ),
('B', 2, 'I' ),
('C', 3, 'H' ),
('A', 3, 'I' )) AS Tb(a, b,c);


우아... 쥑인답!!!

쿼리 테스트 할때 구지... 어렵게 할필요가 없네???

또는 Union All 걸어가면서 만들었던것도... 이제 바이 바이.. ~

 EX )

SELECT NM, SUM( SM ) SM, ISNULL( MAX(H)+'/', '' ) + ISNULL( MAX(I) , '' ) HI
FROM
(
 SELECT NM, SUM( SMALL ) SM , case KIND when 'H' then 'H' end  H, case KIND when 'I' then 'I' end  I
 FROM
 (
  SELECT NM, SMALL, KIND
  FROM (VALUES
  ('C', 1, 'H' ) ,
  ('C', 2, 'I' ),
  ('C', 3, 'H' ),
  ('B', 2, 'H' ),
  ('B', 3, 'H' ),
  ('B', 2, 'I' ),
  ('C', 3, 'H' ),
  ('A', 3, 'I' )) AS Tb( NM, SMALL, KIND )
 ) O
 GROUP BY NM, KIND
) M
GROUP BY NM


이것도 키 등록 후 테이블 내용을 볼때 컬럼명이 아닌 이름으로 볼수있다...

단점, WHERE 문... ㅡ.,ㅡ;;


/*     
   
 윤지송    
    
 테이블의 데이타를 1000개를 쿼리 하되      
      
 컬럼명을 HEADER 가 등록된 테이블은 해당 테이블의 헤더를 컬럼명으로 사용함.      
     
*/     
CREATE PROC dbo.sp_table_select     
 @TABLE_NM NVARCHAR(776)  = ''    
as     
     
IF( RTRIM(@TABLE_NM) = '' OR @TABLE_NM IS NULL )     
BEGIN     
 PRINT(' ^ ______ ^')   
 RETURN;   
END     
     
      
DECLARE @QUERY NVARCHAR(MAX)     
SET @QUERY = ''     
      
 ;WITH TABLE_COLS ( COLUMN_ID, NAME  )     
 AS     
 (     
 SELECT COLUMN_ID, NAME     
 FROM SYS.COLUMNS     
 WHERE OBJECT_ID = OBJECT_ID( @TABLE_NM )     
 ),     
 COLS_ATTS ( NAME , HEADER )     
 AS     
 (     
 SELECT objname AS NAME , value AS HEADER         
 FROM fn_listextendedproperty (NULL, 'schema', 'dbo', 'table', @TABLE_NM, 'column', default)     
 )      
 SELECT-- C.COLUMN_ID,C.NAME, ISNULL(A.HEADER, '') HEADER,     
  @QUERY = @QUERY + C.NAME +  ISNULL( ' AS [' + CONVERT(VARCHAR(100),  A.HEADER ) + ']' ,' AS '+ C.NAME ) + ', '      
 FROM TABLE_COLS C LEFT OUTER JOIN COLS_ATTS A     
 ON C.NAME = A.NAME  COLLATE  Korean_Wansung_CI_AS     
      
--SELECT @QUERY      
EXEC( 'SELECT TOP 100 '+ @QUERY + ' '''' AS [END__]' + 'FROM '+ @TABLE_NM )


 
DECLARE @TABLE_NAME NVARCHAR(776)
SET @TABLE_NAME = PARSENAME( '테이블 명' , 1 )

select COUNT( column_id ) from sys.columns
where OBJECT_ID = OBJECT_ID(@TABLE_NAME)

SELECT
a.name, b.value,
case when b.name is null then '' else
'EXEC sys.sp_dropextendedproperty '+
'@name=N''MS_Description'', '+
'@level0type=N''SCHEMA'', @level0name=N''dbo'', '+
'@level1type=N''TABLE'', @level1name=N'''+OBJECT_NAME(a.OBJECT_ID)+''', '+
'@level2type=N''COLUMN'', @level2name=N'''+a.NAME+'''' end as DropEx,

'EXEC sys.sp_addextendedproperty '+
'@name=N''MS_Description'', @value=N'''+'{0}'+''', '+
'@level0type=N''SCHEMA'', @level0name=N''dbo'', '+
'@level1type=N''TABLE'', @level1name=N'''+OBJECT_NAME(a.OBJECT_ID)+''', '+
'@level2type=N''COLUMN'',@level2name=N'''+a.NAME+'''' as AddEx
FROM sys.columns a
left outer join
(
 SELECT OBJECT_ID( @TABLE_NAME ) object_id , objtype, objname , name, value
 FROM fn_listextendedproperty (NULL, 'schema', 'dbo', 'table', @TABLE_NAME, 'column', default)
-- order by object_id, objname COLLATE  Korean_Wansung_CI_AS asc
) b
on a.object_id = b.object_id and a.name COLLATE  Korean_Wansung_CI_AS = b.objname COLLATE  Korean_Wansung_CI_AS
WHERE a.OBJECT_ID = OBJECT_ID(@TABLE_NAME)


-- 테이블 설명 추가...

EXEC sys.sp_addextendedproperty
@name = N'MS_Description',
@value = N'테이블 추가 설명 ex',
@level0type = N'SCHEMA', @level0name = dbo,
@level1type = N'TABLE',  @level1name =  '테이블 명' ;

SELECT OBJECT_ID(  '테이블 명' ) object_id , objtype, objname , name, value
FROM fn_listextendedproperty(NULL, 'schema', 'dbo', 'table',  '테이블 명', default, default)
where name = 'MS_Description'

 


전에 만들어둔게 있었는데....

문제가 조금 있으니 쿼리를 수정함...

이 프로시져는 등록한 데이타 베이스에서만 사용이 가능하다.

전체 DB에서 사용할 수 있는 방법을 찾아봐야겠다.

-- TAG 검색 되게 PRMS, prms

수정 PK , FK ... 정보 출력.

/*   
작성자 : 윤지송    
   
테이블 컬럼의 속성 보는 쿼리!!   
   
   
SqlManagement Studio에 도구 -> 옵션 -> 일반탭 : 키보드    
   
매크로 지정하는 화면에서    
   
키에 exec SP_TABLE_COLUMN_INFO 를 입력해두고...   
   
쿼리실행창에서 보고싶은 테이블이름 셀렉팅 하고 매크로 키를 누르면 프로시져가 실행되어진다.    
   
단, 키등록후 매니져를 껐다 켜야 되드랑!!    
   
*/   
ALTER PROC DBO.SP_TABLE_COLUMN_INFO   
(   
 @TABLENAME nvarchar(776) = NULL   
)   
AS
 
 
 select distinct
  c.object_id , c.name,
   ltrim( rtrim( case when isnull( index_col( @TABLENAME , i.index_id, C.column_id ),'') <> '' then 'PK' else '' end + ' '+
  case when isnull( f.constraint_column_id , '' ) <> '' then 'FK' else '' end )) as [KEY] ,
  isnull(e.value,'') ExName , isnull( t.name ,'') TypeName,   
  c.COLUMN_ID,                
  CONVERT( VARCHAR,  c.NAME ) AS[NAME],               
  UPPER(t.NAME) AS [DTYPE] ,               
  CASE WHEN UPPER(t.NAME) IN ('CHAR','VARCHAR','NVARCHAR','NCHAR','TEXT' )  THEN CASE c.MAX_LENGTH WHEN -1 THEN '(MAX)'    
          ELSE '('+ CONVERT( VARCHAR, c.MAX_LENGTH / ( CASE WHEN LEFT(t.NAME,1) = 'N' THEN 2 ELSE 1 END ) ) +')'     
        END    
   WHEN UPPER(t.NAME) IN ('NUMERIC','DECIMAL' ) THEN '('+ CONVERT(VARCHAR, c.PRECISION) + ',' + CONVERT(VARCHAR, c.SCALE)+')'   
   ELSE ''    
  END AS [LEN],               
  '-- ' + isnull( CONVERT( VARCHAR,  e.VALUE  ) , c.Name ) AS [DESC],               
                
  '@'+CONVERT( VARCHAR,  c.NAME )+' ' + UPPER(t.NAME) +  CASE WHEN UPPER(t.NAME) IN ('CHAR','VARCHAR','NVARCHAR','NCHAR') THEN CASE c.MAX_LENGTH WHEN -1 THEN '(MAX)'    
            ELSE '('+ CONVERT( VARCHAR, c.MAX_LENGTH / ( CASE WHEN LEFT(t.NAME,1) = 'N' THEN 2 ELSE 1 END ) ) +')'    
          END    
           WHEN UPPER(t.NAME) IN ('NUMERIC','DECIMAL' ) THEN '('+ CONVERT(VARCHAR, c.PRECISION) + ',' + CONVERT(VARCHAR, c.SCALE)+')'   
           ELSE ''    
      END +    
   ', -- ' + isnull( CONVERT( VARCHAR,  e.VALUE  ) , '') AS  PROC_PRMS,   
             
  '@'+CONVERT( VARCHAR,  c.NAME + ',' ) AS [PRMS] ,          
          
  'AND'  AS [AND],         
  CONVERT( VARCHAR,  c.NAME + ' = ' ) + '@'+CONVERT( VARCHAR,  c.NAME  ) AS [WPRMS]       
  ,   
  '' as ['        공백         ']   
  ,c.*       
 from sys.columns c left outer join sys.extended_properties e   
 on c.Object_id = e.MAJOR_ID and c.Column_Id = e.Minor_id and e.CLASS = 1   
 left outer join SYS.TYPES t     
 on c.SYSTEM_TYPE_ID = t.SYSTEM_TYPE_ID AND t.NAME <> 'SYSNAME'   
 left outer join sys.index_columns i
 on c.object_id = i.object_id and c.column_id = i.column_id
 left outer join  sys.foreign_key_columns f
 on c.object_id = f.parent_object_id and c.column_id = f.parent_column_id
 where c.Object_id = OBJECT_ID( @TABLENAME )   
 ORDER BY C.column_id
   
SELECT OBJECT_ID(OBJNAME) OBJECT_ID , objtype, objname , name, value 
FROM fn_listextendedproperty (NULL, 'schema', 'dbo', 'table', @TABLENAME, default, default)

 


음 아래처럼 하면 가져온다.


출처 : http://translate.google.co.kr/translate?hl=ko&langpair=en%7Cko&u=http://wiki.lessthandot.com/index.php/Get_The_Domain_Name_Of_Your_SQL_Server_Machine_With_T-SQL

DECLARE @DOMAINNAME NVARCHAR(100)
EXEC MASTER.DBO.XP_REGREAD
    'HKEY_LOCAL_MACHINE',
    'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon',
    N'CachePrimaryDomain',    
    @DOMAINNAME OUT

SELECT @DOMAINNAME


 


오라클 강좌를 보면서 멋지다 생각했던 쿼리를 ms-sql로 바꾸어 보았다.

물론 이 쿼리는 테스트용도로 변경한 쿼리임.




select  (case [key] when '1' then ' '+t.[name] else '합계' end ) [구분],  
           sum( a ) [a합계],
           sum( b ) [b합계]
from
(
 select 'a' name, 1 a , 2  b
 union all
 select 'b' name, 1 a , 2  b
 union all
 select 'c' name, 1 a , 2  b
)t,
(
 select '1' [key]
 union all
 select '2' [key]
)u
group by ( case [key] when '1' then ' '+t.name else '합계' end )
 

굵게 표시된 그룹바이 키는 동일하게 적용되어야 표시가 된다.

결과 :




## 집합 적인 사고!!! 카티션곱!!


문제가 좀 있는 쿼리로.. 해결방법을 고민중...


부서 정보를 끌어올리고  사용자 정보를 모아서

부서별 직원정보를 만든 후

>>  각 직원별 자기 상급자들을 하나의 컬럼에 순서대로 나열하고자 만든 쿼리이나..

>> 중간 부서에 다수의 상급자가 존재 시 이하 부서직원들의 갯수가 뻥튀기 되는 현상이 CTE에서 발생하는데

이를 해결할 다른 방법은 없는 것일까???



declare @BaseDept table
(
 deptcode varchar(40 ),
 parentdeptcode varchar(40),
 deptname varchar(40)
)

insert into @BaseDept values( '000', null ,  '플랜트')
insert into @BaseDept values( 'a00', '000' , '공장1')
insert into @BaseDept values( 'b00', '000' , '공장2')
insert into @BaseDept values( 'c00', 'a00' , '검사')
insert into @BaseDept values( 'd00', 'a00' , '조립')
insert into @BaseDept values( 'e00', 'c00' , '수리')
insert into @BaseDept values( 'f00', 'b00' , '출하')

declare @BaseUser table
(
 userId varchar(40),
 deptcode varchar(40),
 userName varchar(100)
)

insert into @BaseUser values ( 'u01', '000' , '사장1' )
insert into @BaseUser values ( 'u02', 'a00' , '공장1장장' )
insert into @BaseUser values ( 'u03', 'b00' , '공장2장장' )
insert into @BaseUser values ( 'u04', 'c00' , '테스터' )
insert into @BaseUser values ( 'u05', 'd00' , '조립맨' )
insert into @BaseUser values ( 'u06', 'e00' , 'A/s맨' )
insert into @BaseUser values ( 'u07', 'f00' , '오라이' )
insert into @BaseUser values ( 'u08', 'a00' , '잉여' )

declare @ttt table ( userid varchar(40) )


;with dept( deptcode , parentdeptCode , deptname , lvl , sort )as

 select  deptcode , parentdeptCode , deptname , 0 , cast( deptcode as varbinary(900))
 from @BaseDept
 where deptcode = '000'
 union all
 select a.deptcode , a.parentdeptCode , a.deptname , lvl + 1 , cast( sort + cast( a.deptcode as binary(3) ) as varbinary(900))
 from @BaseDept a inner join dept b
 on a.parentdeptCode = b.deptcode
)
, [user]( userid , deptcode , userName )as

 select userid , deptcode , userName from @BaseUser
)

, dept_user( deptcode , parentdeptCode , deptname , lvl , sort,   userid , userName)as
(
 
 select a.deptcode , a.parentdeptCode , a.deptname , a.lvl , a.sort,   b.userid , b.userName
 from dept a left outer join [user] b on a.deptcode = b.deptcode
)
 
select  row_number() over( order by b.deptcode ),  replicate( '.------> ',  lvl ) + deptName [Tree] , b.deptcode , parentdeptCode , deptname , lvl , sort,   userid , userName, cnt, no
from  dept_user  b
left outer join
(
 select  row_number() over (order by deptcode, userid ) no,  deptcode , count( 1 ) cnt
 from  dept_user
 group by deptcode, userid
) c
on b.deptcode = c.deptcode
order by sort


--/* 각자의 상급자 컬럼을 추가 */
--
--,aboveDept_user ( [no], [no2], deptcode , parentdeptCode , deptname , ltl , srt ,   userid , userName , aboveuser  ) as
--(
-- select  cast( row_number() over( order by userid ) as int), 100,  deptcode , parentdeptCode , deptname , 0 , cast( deptcode as varbinary(900)) , userid ,  userName , cast( '/' + userName as varchar(3000))
-- from dept_user
-- where deptcode = '000'
-- union all
-- select  au.no , cast( row_number() over( order by du.userid ) as int) no2,  du.deptcode, du.parentdeptCode, du.deptname , ltl +1 , cast( srt + cast( du.deptcode as binary(3) ) as varbinary(900)) ,   du.userid , du.userName, cast( aboveuser + '/' + du.username as varchar( 3000 ))
-- from dept_user du inner join aboveDept_user au
-- on  du.parentdeptcode = au.deptcode
--)
--
--select replicate( '.------>',  ltl ) + deptName [Tree] , *
--from aboveDept_user ms
--inner join
--(
-- select deptcode, max( isnull( case when no = 1 then  userid+'('+ username+')' else '' end  , '') ) +  max( isnull( case when no = 2 then  userid+'('+ username+')' else '' end  , '') ) as [desc]
-- from aboveDept_user
-- group by deptcode 
--) sl
--on ms.deptcode = sl.deptcode
----order by srt;


옛날 꼰날... 작업하던중

XML을 통째로 DataTable에 쿼리 하려고 했던적이 있었는데...

잊어버렸다가... 지금 하는 일에 다시 적용해야 될 사항이 생겨서 찾아서 예제로 남김.

어려운거 없다...

-- 예제 결과



-- XML 데이타

<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <INFO>
    <SEQ>1</SEQ>
    <OLDNM>a군</OLDNM>
    <NEWNM />
  </INFO>
  <INFO>
    <SEQ>2</SEQ>
    <OLDNM>b군</OLDNM>
    <NEWNM />
  </INFO>
  <INFO>
    <SEQ>3</SEQ>
    <OLDNM>c군</OLDNM>
    <NEWNM />
  </INFO>
</ROOT>




-- 예제 소스
DECLARE @INFO TABLE
(
    SEQ  VARCHAR(100),
    NM  VARCHAR(100)
)

 

INSERT INTO @INFO VALUES ('1', 'a군' )
INSERT INTO @INFO VALUES ('2', 'b군' )
INSERT INTO @INFO VALUES ('3', 'c군' )

SELECT SEQ, NM as OLDNM, '' [NEWNM] FROM @INFO


DECLARE @XML XML

SET @XML = REPLACE( (SELECT SEQ, NM as OLDNM, '' [NEWNM] FROM @INFO  FOR XML PATH('INFO'), ROOT ('ROOT')) , '<ROOT>' , '<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >')

SELECT @XML AS [XML]

declare @RegistXML XML
set @RegistXML = '
<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <INFO>
    <SEQ>1</SEQ>
    <OLDNM>a군</OLDNM>
    <NEWNM>x군</NEWNM>
  </INFO>
  <INFO>
    <SEQ>2</SEQ>
    <OLDNM>b군</OLDNM>
    <NEWNM>b군</NEWNM>
  </INFO>
  <INFO>
    <SEQ>3</SEQ>
    <OLDNM>c군</OLDNM>
    <NEWNM></NEWNM>
  </INFO>
</ROOT>'

SELECT
 M.Item.query('./SEQ').value('.','VARCHAR(100)') SEQ,
 M.Item.query('./OLDNM').value('.','VARCHAR(100)') [OLDNM],
 M.Item.query('./NEWNM').value('.','VARCHAR(100)') [NEWNM]
FROM @RegistXML.nodes('/ROOT/INFO') AS M(ITEM)

UPDATE @INFO
SET NM = T.[NEWNM]
FROM  (
  SELECT
   M.Item.query('./SEQ').value('.','VARCHAR(100)') SEQ,
   M.Item.query('./OLDNM').value('.','VARCHAR(100)') [OLDNM],
   M.Item.query('./NEWNM').value('.','VARCHAR(100)') [NEWNM]
  FROM @RegistXML.nodes('/ROOT/INFO') AS M(ITEM)
) T
INNER JOIN @INFO B
ON T.SEQ = B.SEQ and T.[NEWNM] <> ''

SELECT * FROM @INFO

/* XML을TABLE로*/
 
--SELECT * FROM TB_BASE_USER
--WHERE USER_NM LIKE 'KCC%'

반대로 table을 다시 xml로 바꿀때

declare @xxx xml = '<ROOT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' + ( SELECT * FROM @INFO FOR XML PATH ('INFO') ) + '</ROOT>'
 
select @xxx


[쿼리1.]

SELECT CNT, CASE WHEN 4 <= RET AND RET  <= 7 THEN 1 ELSE 0 END RET, CASE WHEN 6 <= [PLAN] AND [PLAN] <= 10 THEN 1 ELSE 0 END PL
FROM @TABLE
WHERE RET BETWEEN 4 AND 7  OR [PLAN] BETWEEN 6 AND 10

SELECT ISNULL(SUM( CASE WHEN RET = 1 THEN CNT ELSE 0 END ),0) RETSUM , ISNULL(SUM( CASE WHEN PL = 1 THEN CNT ELSE 0 END ),0) PLANSUM
FROM(
  SELECT CNT,  CASE WHEN 4 <= RET AND RET  <= 7 THEN 1 ELSE 0 END RET, CASE WHEN 6 <= [PLAN] AND [PLAN] <= 10 THEN 1 ELSE 0 END PL
  FROM @TABLE
  WHERE (RET BETWEEN 4 AND 7  OR [PLAN] BETWEEN 6 AND 10)  
)K

[쿼리2.]

SELECT  SA, SB
FROM
(
  SELECT 'A' [KEY], SUM( CNT ) SA
  FROM @TABLE
  WHERE RET BETWEEN 4 AND 7 
) A
INNER JOIN
(
  SELECT 'A' [KEY],  SUM( CNT ) SB
  FROM @TABLE
  WHERE [PLAN] BETWEEN 6 AND 10  
)B
ON A.[KEY] = B.[KEY]

실행계획




http://aseuka.tistory.com/entry/MS-SQL  이 글에 이어 써본다.

위 두 쿼리 결과는 동일하게  4, 5가 나온다.

다만 테이블을 1번 읽었을때와 2번읽었을때를 비교해보기 위해 이글을 써보며

아직 해당 지식이 완전하게 흡수하지 못한점을 미리 써둔다. 


일단 IO가 많이 발생하면 쿼리 개선이 필요하다고 하니... 
                               1번 쿼리                       2번 쿼리
IO 비용                 :    0.0032035                      (0.003125 * 2) 

또 마지막 결과에 대한 트리비용에 대해 확인해보자
                                1번 쿼리                       2번 쿼리 
예상 하위 트리비용 :    0.0032846                      0.0065743

Sort는 둘다 일어나지 않는다!





수치적으로 두배정도 차이나는데

2번 쿼리는 굳이 필요없는 Nested Loops 를 하고 있는 점.
동일 쿼리를 2번 행하고 있는것... 그림으로만 봐도 두배는 걸리는게 맞을것이다.

전에도 실행계획을 보다 보다 모르는게 많아서 패스 했는데

이참에 찾아서 정리해야겠다.

? Stream Aggregate
? Compute Scalar
? Nested Loops

Hash.. 어쩌고 저쩌고.. 참 많은뎁!!