최근 포토로그


MS-SQL에서 MERGE INTO 카운팅 세기 0

알다시피 MERGE INTO는 아무도 모르게 한꺼번에 처리하는 특성때문에 몇개가 추가되고, 몇개가 수정되고, 몇개가 삭제되었는지 확인하기가 힘들다.

내가 쓴 거에 보면, 오라클은 패키지 만들어서 하면 카운팅이 된다.

그런데 MSSQL은?

$ACTION 이라는 강력한

BEGIN TRAN


    CREATE TABLE #T
     ( CHANGE_TYPE VARCHAR(100)
     )

    -- 재고업데이트
    MERGE INTO ITEM_STOCK STK
    USING ( SELECT PLANT_CD
                  ,FACT_CD
                  ,LOCATION
                  ,MAT_CD
                  ,STORE
                  ,SUM(INOUT_QTY) STOCK_QTY
              FROM ITEM_INOUT
              GROUP
                BY PLANT_CD
                  ,FACT_CD
                  ,LOCATION
                  ,MAT_CD
                  ,STORE
          ) TMP
       ON ( STK.PLANT_CD = TMP.PLANT_CD AND
            STK.FACT_CD  = TMP.FACT_CD AND
            STK.LOCATION = TMP.LOCATION AND
            STK.MAT_CD   = TMP.MAT_CD AND
            STK.STORE    = TMP.STORE
          )
     WHEN MATCHED AND STK.STOCK_QTY <> TMP.STOCK_QTY THEN
           UPDATE SET STK.STOCK_QTY = TMP.STOCK_QTY
                     ,STK.UPT_USER  = 'SYS_RECALC:' + CONVERT(VARCHAR(20), STK.STOCK_QTY)
                     ,STK.UPT_DATE  = GETDATE()
     WHEN NOT MATCHED THEN
          INSERT ( PLANT_CD     -- 사업장
                  ,FACT_CD      -- 공장
                  ,LOCATION     -- 창고위치
                  ,MAT_CD       -- 품목코드
                  ,STORE        -- 창고
                  ,STOCK_QTY    -- 재고수량
                  ,UPT_USER     -- 수정자
                  ,UPT_DATE     -- 수정일
                   )
          VALUES ( TMP.PLANT_CD
                  ,TMP.FACT_CD
                  ,TMP.LOCATION     -- 창고위치
                  ,TMP.MAT_CD       -- 품목코드
                  ,TMP.STORE        -- 창고
                  ,TMP.STOCK_QTY    -- 재고수량
                  ,'SYS_RECALC'     -- 수정자
                  ,GETDATE()        -- 수정일
                  )
--SEE ACTION
OUTPUT $ACTION
 INTO #T;

 SELECT CHANGE_TYPE, COUNT(*) CNT FROM #T
 GROUP BY CHANGE_TYPE
 ;
ROLLBACK TRAN


이런식으로 결과값을 볼수있고

--SEE ACTION
OUTPUT $ACTION
 INTO #T;

 SELECT CHANGE_TYPE, COUNT(*) CNT FROM #T
 GROUP BY CHANGE_TYPE
 ;
이것 대신에

--SEE ACTION
OUTPUT $action, Inserted.*, Deleted.*;

이부분을 넣으면
이런 식으로 수정되거나 추가된 레코드를 볼 수 있다.

귀찮아서 쓰는 ROW_NUMBER() 0

, ROW_NUMBER() OVER(PARTITION BY STATION_NO ORDER BY IN_TM ASC) AS SEQ

PARTTION BY 는 그룹이라고 보면 되고,
ORDER BY 는 순서다


문법 헷갈리지 말자



OXCE, Openxcom을 다시 시작해 보았다. 0

심심해서 간단하게 해보자고 시작했는데, 난관이 좀 있다.

문제는 오리지날 xcom TFTD 심해의 공포는 내가 원래 수퍼휴먼으로 해도 심심하면 깼는데,
요즘 버전의 xcom은 문제가 심각했다.

1. deepone의 무기세기가 심각하게 증가했다.
  -> 이게 큰 문제인데, 이놈을 생포하지 않으면 진행이되지 않는다. 그래서 희생을 무릅쓰고 생포해야 하는데, 이놈 생포하려면, 희생이 필요한데, 탱크도 이놈 한방에 죽는 극악한 세기로 만들어서 희생없이 잡기 힘들다는 거다.

2. 외계인 출현빈도가 너무 낮다.
  -> 외계인 미션이 많이 나타나야, 성공해서 돈을 벌어 적자 메꾸고, 시설건설해서 테크트리 빨리 올릴 수 있는데,
     외계인이 잘 안나타나도록 설정했는지 진짜 더럽게 안나타난다. 적자보기 딱 쉽다.

3. 외계인 난이도가 급증했다.
  -> 배틀필드에서 씨불놈들 외계인이 너무 잘 숨고 잘 공략해서 폭탄도 쎄지만, 숨었다고 공격하는게, 사람같고, 거기다가 시야만 확보되면, 폭탄에 유도미사일을 발사한다. 거기다 떼로 덤벼든다.

철인모드와 수퍼휴먼모드를 동시에 사용하는데, 이게 저장질이 안되니깐, 몰살엔딩이 너무 쉽게 나오네...

한마디로 디게 힘들다.

웰케 난이도 높아졌냐...

PostgreSQL 을 MSSQL로 링크드서버 연결하기 0

최근 PostgreSQL 때문에 삽질한 경험을 공유하고자 한다.

우선 mssql에서 PostgreSQL에 연결하려면 ODBC가 있어야 한다.


최신 ODBC 드라이버 다운로드

또는 이 FTP 사이트(https://www.postgresql.org/ftp/odbc/versions/msi/)에서 직접 최신 버전의 PostgreSQL ODBC 드라이버(psqlODBC)에 대한 Windows Installer를 다운로드합니다. .zip 파일에서 파일을 추출하여 .msi 파일을 실행합니다.


32비트와 64비트를 잘 구분하여


13버전쯤이 지금으로는 최고 버전이니 보고 깔면된다.



깔고나면 제어판->관리도구 -> ODBC 데이터원본 (32비트) 혹은(64비트)가 있는데, 각자 운영체제에 맞는 걸 깔면된다.




깔고 나면 시스템 DSN에서 추가버튼을 누른다.



여기서 ansi쓸일 없으니 유니코드 버전의 32bit혹은 60bit를 선택한다.




디폴트로는 이렇게 뜬다.


여기에서 Data Source는 귀찮으니깐 접근하려는 DB명을 쓰는게 좋다.

아니면 최대한 간단한거

Database는 DB명

Server는 IP

Port는 설치시 포트 : 기본값(5432)

User Name : 사용자

Password : 암호



뭐 이런식으로 쓰면 된다.


그런 후 테스트를 누르면 언제나 그렇듯 심심하면 에러가 난다.

postgres FETAL: no pg_hba.conf entry for host SSL off

이 에러가 뜬다면

https://jjiiinn.tistory.com/23


여기 처럼


postgresql에서 pg_hba.conf라는 파일을 수정하면 된다고 한다.

해당 파일을 찾아서 제일 마지막줄에

host  all  all 0.0.0.0/0 md5

를 추가해주면 된다.
구글링해보니 경로가 /var/lib/pgsql/data/pg_hba.conf
pc같은 경우는 c/programFiles/postgresql/9.4/data/pg_hba.conf



이걸 한 후 반드시 서비스에서 PostgreSQL을 다시 시작해야한다.




이정도만 하면 테스트가 문제없이 된다.

그런 이후에 mssql의 ODBC를 연결해야 한다.


MSSQL 의 SSMS를 띄워서 MSDSSQL의 allow inprocess를 체크한 후





링크드 서버 추가를 눌러서






login계정과 암호넣고



옵션에 true 몇개만 하면된다.


그후

이런 식으로 openquery형식으로 하면 조회가 된다.

그냥 조회는 안되고 반드시 오픈쿼리 형식으로 해야 하는 이유가 odbc방식이라서 그런지, postgreSQL이라서 그런지 모르겠지만
다이렉트로는 접근하면 에러 뜬다.

MSSQL 에서 Getdate()함수로 얻은 포맷 자유로이 변환하기 0

MSSQL 에서 Getdate()함수로 얻은 포맷 자유로이 변환하기

http://aslike.egloos.com/1627250

--Getdate()
Select Getdate()

--YYYY/MM/DD
Select Convert(varchar(10),Getdate(),111)

--YYYYMMDD
Select Convert(varchar(10),Getdate(),112)

--HH:MM:SS
Select Convert(varchar(8),Getdate(),108)

--HH:MM:SS:mmm
Select Convert(varchar(12),Getdate(),114)

--HHMMSS
Select Replace(Convert(varchar(8),Getdate(),108),':','')

--HHMMSSmmm
Select Replace(Convert(varchar(12),Getdate(),114),':','')

--YYYY/MM/DD HH:MM:SS
Select Replace(Convert(varchar(30),Getdate(),120),'-','/')

--YYYY/MM/DD HH:MM:SS
Select Replace(Convert(varchar(30),Getdate(),121),'-','/')

--YYYY/MM/DD HH:MM:SS
Select Convert(varchar(10),Getdate(),111) + Space(1) + Convert(varchar(8),Getdate(),108)

--YYYYMMDDHHMMSS
Select Convert(varchar(10),Getdate(),112) + Replace(Convert(varchar(8),Getdate(),108),':','')

SP_HELPTEXT ssms 쿼리결과 물에 TAB이 스페이스로 바뀌는 문제 0

드디어 이상한 현상을 한번에 해결할 방법을 찾았다.

각설하고 이걸 체크하지 않고 SP_HELPTEXT 의 결과를 보면


그런데 이걸 체크하고 새창 열어서 SP_HELPTEXT 를 실행하면

그리드에서는 TAB이 빠져서 보이고, SPACE로 줄간격이 이상하게 되는 현상이
체크 후 복사 붙여넣기 하면 TAB까지 잘 보인다.



pig toolbox에서 오류를 뱉어낼때 0

pig toolbox가 크롬을 공식지원하지 못하는 관계로 강제로 확장 프로그램으로 올리면
debug.log를 수없이 만들어 낸다.


너무 짜증나는 일이지만, 그게 크롬 정책이니깐...


이렇게 하면 된다.


MSSQL 에서 숫자를 소수점 없애서 문자형으로 리턴하기 0

함수로 만들었다.

쓰고 싶으면 쓰시라.

CREATE FUNCTION [DBO].[FN_GET_NUM2STR]
--◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆
--◆              (c) Copyright DongSeoIT Co.,LTD.  2016
--◆                   All rights reserved
--◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆
--◆ Program Code   :  FN_GET_NUM2STR
--◆ Date           :  2020. 12. 22.
--◆ Description    :  소숫점 이하 없애는 함수
--◆ Author         : 홍길동
--◆ USED PROGRAM   :  숫자를 표시할만한 스트링
--◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆
--◆ Modification Log
--◆ Date            In Charge    Description
--◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆
--◆ 2020. 12. 22.   홍길동      최초버전
--◆
--◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆◆
/*
◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈
    SELECT DBO.FN_GET_NUM2STR('153.123456789')
    SELECT DBO.FN_GET_NUM2STR('153.100')
    SELECT DBO.FN_GET_NUM2STR('153.000')
◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈◈
*/

(
     @IN_ORG_NUM    NVARCHAR(MAX) = '15.1234515'

)
RETURNS NVARCHAR(50)
AS
BEGIN
    DECLARE @V_SQL       NVARCHAR(MAX)
    DECLARE @V_RTN_VAL   NVARCHAR(MAX)


    IF ISNUMERIC(@IN_ORG_NUM) = 1
    BEGIN
        SELECT @V_RTN_VAL = FORMAT(CONVERT(NUMERIC(25, 10), CONVERT(NUMERIC(25, 10), @IN_ORG_NUM)), '###.##########') 
    END

    RETURN ISNULL(@V_RTN_VAL, '')


END


svn lock 강제해제하기 0

예전버전의 svn은 .lock 파일만 지우면 문제가 안되었는데
요즘버전은 DB4S 파일DB로 되어있다.
고로 그냥은 안된다는 말이다.


https://sqlitebrowser.org/
여기 들어가서 최신버전 다운 받은 후




숨김 항목 보여주기로 한 후
.svn 폴더를 숨김해제한 후에 


DB Browser for SQLite.exe 실행하고

DELETE FROM WC_LOCK
DELETE FROM WORK_QUEUE

실행한 후에 DB저장한다.


그 다음 해당 프로젝트 clean up하면 된다.



zebra에 한글폰트 넣기 1

먼저 2가지 방법이 있다.

1번은 USB를 통하여 출력할때, 쓰는 방법이고
2번은, serial을 통하여 출력할때, 쓰는 방법이다.

1번은 버퍼를 통하여 인쇄를 하며, 출력시 프린터대기창이 뜬다.


이 방법으로 파일을 전송하면 된다.

2번째 방법은 시리얼 포트로 전송하는 것이므로 시간이 많이 걸린다. (대략 20분)
첨부된 파일의 ZEBRA_TO_FONT.bat 를 실행하면 한글 출력을 할수 있는데 (COM7 을 자신의 프린터와 연결된 포트로 바꾼다. ETC: COM1
) COM 포트 번호만 바꾸고 실행하면 된다.



대충 다음과 같은 모습을 거의 20분 가까이 소모할 것이다.










NSIS로 설치파일 만들기 0

NSIS 다운로드 및 설치



스크립트 편집기 다운로드 및 설치
http://hmne.sourceforge.net/

마법사 실행하기





요즘쓰는 SSMS 애드온 0

ApexSQL 이라는 애드온이다.


이게 SQL search 랑 달리 문장내에 한칸 띄워져 있어도 검색이 된다.

단, 단점은 색표시가 안된다.

어느 부분에 이 글자가 있는지, 찾을려고 하면 눈이 고생해야 함.


근데 그것 빼고는 아름다움.

SQL 포멧팅은 상용과 비교될 정도로 아름다운 결과물을 만들어내지만, 셋팅이 복잡하다. (그만큼 다양하다.)

암튼 맘에드는 MSSQL 내용찾는 거라서 추천함.


잘 써서 sp_helptext 를 탈출해보자.






홍미노트8 Pro 직구폰 통화안될때 0



샤오미 전화앱에서 버튼을 간단하게 아래 번호를 입력하고

*#*#86583#*#*

2~3번 재부팅하면 유심이 활성화 된다.!!!



MSSQL 단순 MERGE INTO 1

    MERGE INTO MWIPEXTRES AUT
    USING (SELECT 'X' AS DUAL) DUAL
       ON ( AUT.RES_NO  = @IN_RES_NO
          )
    WHEN MATCHED THEN
              UPDATE SET UPTUSER = @IN_UPD_ID
                             ,UPTDATE = GETDATE()
    WHEN NOT MATCHED THEN
          INSERT ( RES_NO
                  ,KIT_LOT_NO
                  ,SEQ
           )
          VALUES ( @IN_RES_NO
                  ,@IN_KIT_LOT_NO
                  ,1
                  ); 

뭐 이런식으로 쓰면 된다.
이건 조인을 사용하지 않는 문장이고, 조인을 사용한다면 
SELECT 'X' AS DUAL 
구문을 SELECT TABLE문으로 바꾸면 된다.

카톡 PC버전 너무 짱나네 이거 2

몇달전부터 카톡 PC버전에서 이미지가 잘 수신이 안된다.

다 안되면 그런가보다 하는데, 몇개는 오고 몇개는 안온다.

이런게 진짜 미치는 거지



해결방법이 없나?


MERGE INTO 를 극복해보자 0

내가 구세대라서 그런지 쿼리를 좀 보수적으로 하는 경향이 있다.

즉, 
MERGE INTO 나 CTE같은 거 잘 안쓰려고 하더라구, 근데 어쩔수 없이 써야 하는 경우에는 쓰는데
자꾸 문법이 헷갈린다. 그래서 써본다. MERGE INTO 문법

MSSQL 의 경우



        MERGE INTO 엄청난테이블 MST
        USING (SELECT 'X' AS DUAL) DUAL
           ON (     PLANT_CD    = @IN_PLANT_CD
                AND FACT_CD     = @IN_FACT_CD
                AND WORD_NO     = @IN_WORD_NO
                AND INSP_CYCLE  = @IN_INSP_CYCLE
              )
         WHEN MATCHED THEN
              UPDATE SET OK_DECISION = @V_OK_DECISION
                        ,INSP_DATE   = GETDATE()
                        ,INSP_DAY    = @V_DT 
                        ,INSP_TM     = @V_TM
                        ,INSP_ID     = @IN_CHECK_ID 
                        ,UPTDATE     = GETDATE()
                        ,UPTUSER     = @IN_USER_ID
         WHEN NOT MATCHED THEN
              INSERT ( PLANT_CD
                      ,FACT_CD
                      ,INSITEM_CD
                      ,REVISION
                      ,INSP_CYCLE
                      ,WORD_NO
                      ,MAT_CD
                      ,OK_DECISION
                      ,INSP_DATE
                      ,INSP_DAY
                      ,INSP_TM
                      ,INSP_ID
                      ,CRTDATE
                      ,CRTUSER
                       )
              VALUES ( @IN_PLANT_CD
                      ,@IN_FACT_CD
                      ,@IN_INSITEM_CD
                      ,@IN_REVISION
                      ,@IN_INSP_CYCLE
                      ,@IN_WORD_NO
                      ,@IN_MAT_CD
                      ,@V_OK_DECISION
                      ,GETDATE()
                      ,@V_DT
                      ,@V_TM
                      ,@IN_CHECK_ID 
                      ,GETDATE()
                      ,@IN_USER_ID
                      ); 


이 경우는 테이블 조인이나 그런거 필요없이 특정한 칼럼의 값을 위하서 쓰는 문법임.

    MERGE INTO 엄청중요한테이블 AUT
    USING ( SELECT ROLE_CD
              FROM 조인하는테이블
             WHERE DEPT_CD = @IN_DEPT_CD
   AND USE_YN = 'Y'
          ) TMP
       ON ( AUT.USER_ID = @IN_USER_ID AND
            AUT.ROLE_CD = TMP.ROLE_CD
          )
     WHEN NOT MATCHED THEN
          INSERT ( USER_ID          -- 사용자 ID 
                  ,ROLE_CD          -- 권한 코드
                  ,CRTUSER          -- 등록자 ID
                  ,CRTDATE          -- 등록일시
                   )
          VALUES ( @IN_USER_ID
                  ,TMP.ROLE_CD  
                  ,@IN_UPD_ID
                  ,GETDATE()
                  ); 


MSSQL 애드온 (SP_HELPTEXT의 대안) - sp 내용보기 0

여기 글 보신분은 알겠지만 내가 꾸준히도 sp_helptext에 대해 썼다.

그만큼 더러운데 아직까지 안고쳐져서 포기하는 프로시저라는 말이죠.

엔터키 자동입력 문제, 텝정렬 무시 문제... 등등


그래서 그걸 한방에 해결해줄 해결사를 찾았는데, 그건 바로

"SQL Search" 라는 애드온이다.


링크는 아래


이걸 누르면 다운로드 할 수 있다.


그리고 쓰는 방법은 간단하다.

깔면 MSSM에 장착된다.


요로코롬 장착되는데 이걸 가지고 

버튼 누르면 


요렇게 DB를 선택할 수 있고

매칭은
text만 검색할지, 아니면 이름으로 검색할지, 칼럼으로 검색할지가 나온다. SP 내용 검색하는 기능으로 최고다


이걸로는  프로시저, 함수, 뷰 등을 검색할 수 있다.

"Match Whole Word Only" 체크하면 문장으로 검색할 수 있다.

즉, "insert into aaa_tbl" 로 검색하면 
이렇게 검색되는 것이

체크를 하면

글자가 다 있는거만 나온다.

그리고 더블클릭하면 프로시저에 간다.


최고임.

USIM에 대한 고찰 0

내가 해외에 가면 USIM칩 사서 꼽고 통화하는데, 암만 오래걸려도 30분이면 처리가 된다.

근데, 한국은 꼭 단말기를 껐다가 켜야 하고, 기둘려야 하고 이런다.

유심을 왜 이렇게 어렵게 만들어놨는지 모르겠다.
인증절차가 그리 어렵나???

암튼 계속 껐다가 켜야하는 이유를 잘 모르겠다.


그냥 하루동안 통화 안되어서 짜증나서 그랬다.

openxcom(OXCE) 를 다시 시작했다. 0

최근 오리지날 xcom[TFTD)에 확장모드가 있다는 걸 알았다.

TWOTS 라는 건데, 이거 어렵고 오래걸린다.


혹시나해서 superhuman 으로 플레이 했는데, 씨붕 암만 쏴도 안죽는 놈들도 있어서 도저히 superhuman 은 저장질 없이 하는 건 스트레스 만빵이라서 못하겠다.

중간정도 어려움으로 하면 스트레스 없이(?) 할 수 있을 거 같다.

그래도 더럽게 시간 많이 걸린다.

screen003.png


screen003.1.png

인도 AirTell 통신비 0

유심빼고 통신비만 보면 하루 1.5기가에 200루피다 28일 쓸수 있는 것이고...

이거 우리돈으로 환산하면 약, 3360원 정도네....

씨불 디게 싸네.

한국 저렴한 통신사 알아보면 이거 제3통신사를 써도 2배이상이다.

그러고보면 한국 통신비 싸다는 말 개구라임.

인도라서 그렇다고?

그럼 할 말 없지머.





MSSQL 임시테이블 활용하기 0

물론 테이블변수가 작게 쓸려고 하거나 컴파일 하지 않으려고 하면 쓰임새가 많다.

하지만, 
임시테이블 (#)이 붙은 테이블은 쓰기에 따라서 아름다운 결과물을 만들어 낼수 있다.

MSSQL 임시테이블은 #을 하나만 쓴다면 자기영역 내에서는 어디에서든 쓸수 있다.

즉, 내부 프로시저 안과 내가 호출하는 프로시저내에서는 자유롭게 부를 수 있다는 거다.

즉,

아래 셈플을 보자

=============================================================

-- DROP PROC dbo.usp_TableVar
go
CREATE PROC dbo.usp_TableVar

AS

create table #Tb_test 
(

OrderID int identity(1,1) PRIMARY KEY NONCLUSTERED
, OrderDate datetime CHECK (OrderDate >= '1900-01-01')

)

INSERT INTO #Tb_test values ('20180101')
INSERT INTO #Tb_test values ('19910101')

--SELECT TOP 10 OrderDate FROM Orders --OrderID 컬럼은 지정할 필요 없다.


UPDATE #Tb_test SET OrderDate = OrderDate + 1

DELETE #Tb_test WHERE OrderDate > '1996-07-10'

exec usp_TableVar2

SELECT * FROM #Tb_test

GO



-- DROP PROC dbo.usp_TableVar2
go
CREATE PROC dbo.usp_TableVar2

AS


INSERT INTO #Tb_test values ('20180102')
INSERT INTO #Tb_test values ('19910103')
exec usp_TableVar3


GO

-- DROP PROC dbo.usp_TableVar3
go
CREATE PROC dbo.usp_TableVar3

AS


INSERT INTO #Tb_test values ('20180105')
INSERT INTO #Tb_test values ('19910106')

GO

EXEC dbo.usp_TableVar


-- DROP PROC dbo.usp_TableVar
-- DROP PROC dbo.usp_TableVar2
-- DROP PROC dbo.usp_TableVar3

============================

usp_TableVar 프로시저가 usp_TableVar2를 부르고 usp_TableVa3을 부른다.

그럼에도 임시테이블 
#Tb_test 에는 접근 가능하고, 다 추가/수정/삭제 되다.


쿼리결과에 TAB, LF 등이 표결과에서 안 나올때 1

참 간단한 거였는데 이제 알았다.



첫번째꺼에 보면 표로 결과를 보내면 텝키나 라인조정이 이상하게 되어서 결과가 space한개로 바뀌어서
나중에 복사하면 결과물이 이상하게 된다.


즉 

이런 식으로 텝이 있으면 이걸 복사하는 과정에서 mssql은 텝무시가 디폴트로 되어있어서 결국 

이런 방식으로 텝이 없어지면서 거기에 스페이스가 알아서 먹히면서 줄 정렬이 지독하게 이상하게 되는 것이다.

이거를 막기 위해서는 이전에는 짜증나게도 "텍스트 결과로 표시"를 사용했다.

즉,
이렇게 하면 출력이 잘되었지만, 
나는 항상 표로 결과물을 도출하는데, SP 내의 결과를 보기위해서 자꾸 왔다갔다 해야 하는 것 때문에 짜증 지수가 MAX였다.



그런데 오늘 SSMS 설정 좀 건드리다가 알아낸 사실

"복사 또는 저장 시 CR/LF 보존"
이라는 게 결국 그걸 잘 해주는 거였네.

이렇게 하고 새탭 열어서 이래저래 테스트 해보니
표결과는 이상하게 보여도, 복사&붙여넣기를 하면 TAB키도 잘 표시되고 이쁘게 나온다.

이런거 정말 필요했는데 아직도 못했던 내가 미워





MSSQL 의 SSMS 에서 암호저장이 안될 때, 0

보안 문제는 있지만 저장 안되는 버그가 나를 괴롭힌다.

그래서 구글링해보니


C:\Users\사용자\AppData\Roaming\Microsoft\Microsoft SQL Server\140\Tools\Shell
밑의 파일을 삭제하고 다시  ssms 껏다가 켜라고 되어있더라.

해보니 잘된다.


단, 이전 저장한 로그들 싹다 날라간다.


저 위의 
140은 내가 14버전을 쓰고 있어서 그렇다.

버전별로 안에 들어가 있는 파일이 조금 다르더라.

암튼 그쪽 파일 지우면 만사 OK


심심해서 써보는 오픈엑스컴 TFTD - 슈퍼휴먼 난이도. 2

예전에 엑스컴 TFTD 를 슈퍼휴먼 난이도로 클리어한 기억이 있다.

근데 생각해보면 이전 엑스컴의 TFTD는 슈퍼휴먼 난이도라고 해도, 세이브모드가 있었기 때문에 내가 클리어를 쉽게(?) 했던 기억이 있다.

그런에 오픈엑스컴(OpenXcom)는 아이언모드가 있다.

한마디로 저장질(?)을 못하는 버전이다.

근데 이 아이언모드로 하면 빡지는 부분이 밤에 공격하면 시야가 극도로 좁아지는 단점 때문에
낮에 접근하려고 기다려야 하는데, 항구미션, 배미션은 시간지나면 사라지기 때문에 대중 짐작해서 출발해야 한다.

그렇다고 웨이포인트에 기다려도 잘 사라지기 때문에 시간이 빡빡할 경우 그냥 감으로 출동해버리는 수가 많다.
그러다보면 어두운데서 조명탄 던지면서 해야 한다.

예전 처음했던 슈퍼휴먼의 난이도는 고폭탄을 때려도 섹토이드가 죽지 않는 경우도 있었다. - 아니 좀 있었다. - 
그리고 이놈들 흥분하면 심심하면 외계수류탄을 까서 작살나는 경우가 너무 많았다.

다행히(?) 오픈엑스컴에서는 수류탄은 잘 안쓰는데, 갑자기 디스트럽터 펄스 런처를 잘(?) 발사해서 몰살 당하는 경우가 잦더라.

거기다가 오픈엑스컴에서는 초반 2~3월에도 외계인들이 갑자기 기지로 처들어오는 경우가 생겼다.
아예 소닉수류탄 정도만 개발했는데 외계인이 처들어오면 그게 상대가 되냐?

거기다가 5개월 넘어가면 소닉캐논도 개발 안되었는데, 랍스터가 처들어 와서 도저히 답이 없는 경우도 생겼다.


허.... 어쨌거나 오픈엑스컴 TFTD 2018년 9월버전은 수퍼휴면 아이언모드로 할려니 진짜 박시게 해야 한다는 걸 깨달았다.

몇번 당하다가 
지금 3월까지 진행했는데 이거 성공할 것 같다.

나중에 유투브 방송을 할수 있다면 이거 라이브로 방영하는 것도 좋은 거 같다. 
ㅎㅎㅎ


SP_HELPTEXT의 고질적인 문제에 대한 고찰 2

내가 여기에 SP_HELPTEXT 에 대한 글만 여러 개 썼었는데, 항상 문제가 발생하였다.

왜 이런 귀찮은 일을 하는지 물어본다면 추가 라인이 갑자기 생기는 문제 때문이다.

내 작업의 특성상 MSSQL 스토어드프로시저를 많이 쓰는데, 
SSMS를 사용하여 프로시저 수정 을 클릭했을 때랑, SP_HELPTEXT를 사용하여 프로시저를 불렀을때랑 결과물이 다르게 나타나는 문제 때문이다.


이게 한번만 수정하면 상관없는데, 여러번 수정을 거치면 기하급수적으로 이쁘게 만들었던 라인들이 엉망이 되어간다는 점이다.

물론 다른 툴을 사용하면 되겠지만 나는 MSSQL 순정, 거기에 SSMS를 사용하므로 SP_HELPTEXT를 수정하지 않으면
결국 에러를 발생시키거나 아니면 엄청나게 이상한 라인을 참으며 작업을 해야 한다.

그 결과의 셈플 화면이 이건데

위에처럼 "WHERE" 부분이 갑자기 튀어나와서 라인이 엉클러지는 문제이다.


그래서 수정을 거치게 되었는데 그게 SP_HELPTEXT2 인데,
문제는 내가 CREATE PROCEDURE 라는 글자를 매번 ALTER PROCEDURE 라는 글자로 바꾸기 싫다는 거다.

그레서 결과물을 커서로 돌려서 첫째라인을 바꾼 후에 PRINT를 출력하였더니
빈칸에 공백이 한개씩 찍혀나오는 버그를 발겼했다.
씨붕
아래 화면에 적나라하게 나타난다.
스페이스가 한칸씩 있다는 말이지. 또한 PRINT의 특성상 맨 마지막 라인 이후에 엔터키가 하나가 먹힌다.
이쯤되면 짜증이 좀 난다.

그래서 어쩔 수 없이 PRINT 부분을 다시 테이블에 넣고 표형태로 결과물을 찍어야 내가 원하는 결과물을 얻어낼 수 있다는 것을 발견했다.


아름다운 결과물을 먼저 감상하자.
이 화면에서는 잘 안보이지만, 빈라인에 공백 1개씩 추가되는 것도 없고, CREATE PROC를 ALTER PROC로 바꾸어주고
그리고 맨 마지막 라인도 깔끔하게 끝나는 버전으로 완성했다.


기뻐서 이것을 최종버전으로 배포합니다.

쌩유

아래부분은 프로시저입니다. ==================================>
ALTER PROCEDURE SP_HELPTEXT2 (@ProcName NVARCHAR(256))
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @SEQ INT
    DECLARE @TEXT NVARCHAR(4000)

    DECLARE @PROC_TABLE TABLE (X1  NVARCHAR(MAX))


    DECLARE @Proc NVARCHAR(MAX)
    DECLARE @Procedure NVARCHAR(MAX)
    DECLARE @ProcLines TABLE (PLID INT IDENTITY(1,1), Line NVARCHAR(MAX))

    DECLARE @NEW_ProcLines TABLE (PLID INT IDENTITY(1,1), Line NVARCHAR(MAX))

    SELECT @Procedure = 'SELECT DEFINITION FROM ['+db_name()+'].SYS.SQL_MODULES WHERE OBJECT_ID = OBJECT_ID('''+@ProcName+''')'

    insert into @PROC_TABLE (X1)
          exec  (@Procedure)

    SELECT @Proc=X1 from @PROC_TABLE

    WHILE CHARINDEX(CHAR(13)+CHAR(10),@Proc) > 0
    BEGIN
          INSERT @ProcLines
          SELECT LEFT(@Proc,CHARINDEX(CHAR(13)+CHAR(10),@Proc)-1)
          SELECT @Proc = SUBSTRING(@Proc,CHARINDEX(CHAR(13)+CHAR(10),@Proc)+2,LEN(@Proc))
    END
    --* inserts last line
    INSERT @ProcLines
    SELECT @Proc ;

    --SELECT Line FROM @ProcLines ORDER BY PLID


    DECLARE SCRIPTCURSOR9 CURSOR LOCAL FORWARD_ONLY STATIC FOR
        SELECT PLID, Line FROM @ProcLines ORDER BY PLID

    OPEN SCRIPTCURSOR9

    FETCH NEXT FROM SCRIPTCURSOR9 INTO @SEQ, @TEXT

    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF @SEQ <= 1
        BEGIN
            SET @TEXT = REPLACE(@TEXT, 'CREATE PROC', 'ALTER PROC')
            SET @TEXT = REPLACE(@TEXT, 'CREATE FUNC', 'ALTER FUNC')
            SET @TEXT = REPLACE(@TEXT, 'CREATE VIEW', 'ALTER VIEW')
        END
        insert into @NEW_ProcLines 
               SELECT @TEXT
        --PRINT @TEXT

        FETCH NEXT FROM SCRIPTCURSOR9 INTO @SEQ, @TEXT
    END

    CLOSE SCRIPTCURSOR9
    DEALLOCATE SCRIPTCURSOR9

    SELECT Line FROM @NEW_ProcLines ORDER BY PLID

    --DROP TABLE  @ProcLines

END
========================================================

맘 놓고 쓰시라



귀찮아서 쓰는 MSSQL 테이블, SP, 칼럼, 뷰 관련 목록 정보 조회 0

--테이블 목록 가져오기:
SELECT * FROM sysobjects WHERE xtype='U'

--뷰:
SELECT * FROM sysobjects WHERE xtype='V'

--프로시져:
SELECT * FROM sysobjects WHERE xtype='P'


--테이블 리스트
SELECT * FROM  INFORMATION_SCHEMA.TABLES
--뷰 리스트
SELECT * FROM  INFORMATION_SCHEMA.VIEWS
--컬럼 리스트
SELECT * FROM  INFORMATION_SCHEMA.COLUMNS
--컬럼 키값
SELECT * FROM  INFORMATION_SCHEMA.KEY_COLUMN_USAGE

--프로시져
SELECT * FROM INFORMATION_SCHEMA.ROUTINES
--프로시져 파라메타값
SELECT * FROM  INFORMATION_SCHEMA.PARAMETERS

 

--컬럼 정보 가져오기
SELECT
 A.TABLE_CATALOG
 ,A.TABLE_NAME
 ,A.ORDINAL_POSITION
 ,A.COLUMN_NAME
 ,A.DATA_TYPE
 ,ISNULL(A.CHARACTER_MAXIMUM_LENGTH,'')
 ,ISNULL(A.NUMERIC_PRECISION,'')
 ,A.IS_NULLABLE
 ,ISNULL(A.COLUMN_DEFAULT,'')
 ,ISNULL(B.CONSTRAINT_NAME,'')
 ,ISNULL(A.CHARACTER_SET_NAME,'')
 ,ISNULL(A.COLLATION_NAME,'')
 ,CASE WHEN ISNULL(C.NAME,'') = '' THEN '' ELSE 'Identity' END auto
FROM 
 INFORMATION_SCHEMA.COLUMNS A
 LEFT OUTER JOIN
 INFORMATION_SCHEMA.KEY_COLUMN_USAGE B
 ON A.TABLE_NAME = B.TABLE_NAME 
 AND A.COLUMN_NAME = B.COLUMN_NAME
 LEFT OUTER JOIN
 syscolumns C 
 ON C.ID = object_id(A.TABLE_NAME) AND A.COLUMN_NAME = C.NAME AND C.COLSTAT & 1 = 1 
WHERE
 A.TABLE_NAME = '테이블명'
ORDER BY A.ORDINAL_POSITION


SP_HELPTEXT 의 완성판( 줄이 밀리는 현상 해결) 0

SP_HELPTEXT 를 쓰다보면 자꾸 라인이 깨지는 현상이 가끔 가다가 발견한다.

이게 현상의 원인이 무엇인지 알아내지 못해서 몇년동안 고생해서 
차라리 SSMS에서 그냥 수정을 누르거나 라인을 일일이 다시 조정해주고 실행해주는 번거로움을 겪어야 했다.

이거 SP 많이 다루는 사람은 알겠지만, 정말 큰 스트레스다.

그래서 구글링은 몇년동안 지속적으로 한 결과 결국 답을 찾아냈다.


찬양하라 구글신이여!!!!


이제 드디어 SP_HELPTXTX의 버그 없는 판을 만든 것이다.

SP 참조 (참고로 여기 버전은 ALTER PROC부분으로 수정한다든지, 콘솔창에 찍어주는 부분도 포함되었다.
뜯어보시고 수정하시라.


==================================================
CREATE PROCEDURE SP_HELPTEXT2
( @PROCNAME NVARCHAR(256)
)
AS
BEGIN
    SET NOCOUNT ON
    DECLARE @PROC_TABLE TABLE (X1  NVARCHAR(MAX))

    DECLARE @PROC NVARCHAR(MAX)
    DECLARE @PROCEDURE NVARCHAR(MAX)
    DECLARE @PROCLINES TABLE (PLID INT IDENTITY(1,1), LINE NVARCHAR(MAX))
    DECLARE @SEQ INT
    DECLARE @TEXT NVARCHAR(4000)

    SELECT @PROCEDURE = 'SELECT DEFINITION FROM ['+DB_NAME()+'].SYS.SQL_MODULES WHERE OBJECT_ID = OBJECT_ID('''+@PROCNAME+''')'

    INSERT INTO @PROC_TABLE (X1)
          EXEC  (@PROCEDURE)

    SELECT @PROC=X1 FROM @PROC_TABLE

    WHILE CHARINDEX(CHAR(13)+CHAR(10),@PROC) > 0
    BEGIN
          INSERT @PROCLINES
          SELECT LEFT(@PROC,CHARINDEX(CHAR(13)+CHAR(10),@PROC)-1)
          SELECT @PROC = SUBSTRING(@PROC,CHARINDEX(CHAR(13)+CHAR(10),@PROC)+2,LEN(@PROC))
    END
    --* INSERTS LAST LINE
    INSERT @PROCLINES
    SELECT @PROC ;
    -- 이부분을 넣으면 테이블그리드로 나온다.
    --SELECT LINE FROM @PROCLINES ORDER BY PLID


    DECLARE SCRIPTCURSOR9 CURSOR LOCAL FORWARD_ONLY STATIC FOR
        SELECT PLID, LINE FROM @PROCLINES ORDER BY PLID

    OPEN SCRIPTCURSOR9

    FETCH NEXT FROM SCRIPTCURSOR9 INTO @SEQ, @TEXT

    WHILE @@FETCH_STATUS = 0
    BEGIN
        -- 1번라인에 CREATE 부분을 수정
        IF @SEQ <= 1
        BEGIN
            SET @TEXT = REPLACE(@TEXT, 'CREATE PROC', 'ALTER PROC')
            SET @TEXT = REPLACE(@TEXT, 'CREATE FUNC', 'ALTER FUNC')
            SET @TEXT = REPLACE(@TEXT, 'CREATE VIEW', 'ALTER VIEW')
        END
        PRINT @TEXT

        FETCH NEXT FROM SCRIPTCURSOR9 INTO @SEQ, @TEXT
    END

    CLOSE SCRIPTCURSOR9
    DEALLOCATE SCRIPTCURSOR9

    --DROP TABLE  @PROCLINES

END

SSMS(SQL Server Management Studio) 단축키 변경하기 0

MSSQL 의 쿼리서버관리스튜디오는 - 왜 이리 적당한 한글명칭이 없는거야? -
단축키 변경이 좀 특이하다.

예전에 주석처리하기 단축키가 Ctrl+Shift+C, CTRL+Shift+R
이었는데, 이제는 너무 달라져서 두번, 세번 키를 타이핑해야 해서 내가 짜증나서 

Ctrl+Shift+>
Ctrl+Shift+<

로 바꾸기로 했다.

근데 이게 좀 복잡하니 자세히 써본다.

먼저 옵션->환경->키보드로 가면 
편집.선택영역을주석으로처리 가 보인다.


제거를 두번 누르기

그러면 바로가기 키 누리기에서 단축키 넣고 할당 버튼



간만에 xcom2(TFTD)를 superhuan, ironman 으로 했다. 0

간만에 했는데, ironman 이라서 save Load 짓거리를 못하니깐, 조심스럽게 하게 되더라

초반에 Deep one Terror 놈을 못잡아서 고생했는데,
lobster man 나왔으니 10분의 1 정도는 깬거 같다.

근데 이정도 되면 귀찮을 뿐.

mssql에서 table 스크립트 뽑아내기 0

하다보면 알겠지만, create table 스크립트 뽑아내는게 정말 귀찮다.
그래서 구글링을 했다.

나는 dbo나 이런거 붙는 거 극혐하므로, 여러가지 해본 결과 다음의 프로시저가 가장 아름답다는 결론이 났다.

===================================

CREATE procedure USP_CREATE_TABLE_SCRIPT
      @table_name SYSNAME
AS
BEGIN
--DECLARE @table_name SYSNAME
--SELECT @table_name = 'dbo.omm_config'

DECLARE
      @object_name SYSNAME
    , @object_id INT

SELECT
      @object_name = o.name
    , @object_id = o.[object_id]
FROM sys.objects o WITH (NOWAIT)
JOIN sys.schemas s WITH (NOWAIT) ON o.[schema_id] = s.[schema_id]
WHERE o.name = @table_name
    AND o.[type] = 'U'
    AND o.is_ms_shipped = 0

DECLARE @SQL NVARCHAR(MAX) = ''

;WITH index_column AS
(
    SELECT
          ic.[object_id]
        , ic.index_id
        , ic.is_descending_key
        , ic.is_included_column
        , c.name
    FROM sys.index_columns ic WITH (NOWAIT)
    JOIN sys.columns c WITH (NOWAIT) ON ic.[object_id] = c.[object_id] AND ic.column_id = c.column_id
    WHERE ic.[object_id] = @object_id
),
fk_columns AS
(
     SELECT
          k.constraint_object_id
        , cname = c.name
        , rcname = rc.name
    FROM sys.foreign_key_columns k WITH (NOWAIT)
    JOIN sys.columns rc WITH (NOWAIT) ON rc.[object_id] = k.referenced_object_id AND rc.column_id = k.referenced_column_id
    JOIN sys.columns c WITH (NOWAIT) ON c.[object_id] = k.parent_object_id AND c.column_id = k.parent_column_id
    WHERE k.parent_object_id = @object_id
)
SELECT @SQL = 'CREATE TABLE ' + @object_name + CHAR(13) + '(' + CHAR(13) + STUFF((
    SELECT CHAR(9) + ', [' + c.name + '] ' +
        CASE WHEN c.is_computed = 1
            THEN 'AS ' + cc.[definition]
            ELSE UPPER(tp.name) +
                CASE WHEN tp.name IN ('varchar', 'char', 'varbinary', 'binary', 'text')
                       THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length AS VARCHAR(5)) END + ')'
                     WHEN tp.name IN ('nvarchar', 'nchar', 'ntext')
                       THEN '(' + CASE WHEN c.max_length = -1 THEN 'MAX' ELSE CAST(c.max_length / 2 AS VARCHAR(5)) END + ')'
                     WHEN tp.name IN ('datetime2', 'time2', 'datetimeoffset')
                       THEN '(' + CAST(c.scale AS VARCHAR(5)) + ')'
                     WHEN tp.name = 'decimal'
                       THEN '(' + CAST(c.[precision] AS VARCHAR(5)) + ',' + CAST(c.scale AS VARCHAR(5)) + ')'
                    ELSE ''
                END +
                CASE WHEN c.collation_name IS NOT NULL THEN ' COLLATE ' + c.collation_name ELSE '' END +
                CASE WHEN c.is_nullable = 1 THEN ' NULL' ELSE ' NOT NULL' END +
                CASE WHEN dc.[definition] IS NOT NULL THEN ' DEFAULT' + dc.[definition] ELSE '' END +
                CASE WHEN ic.is_identity = 1 THEN ' IDENTITY(' + CAST(ISNULL(ic.seed_value, '0') AS CHAR(1)) + ',' + CAST(ISNULL(ic.increment_value, '1') AS CHAR(1)) + ')' ELSE '' END
        END + CHAR(13)
    FROM sys.columns c WITH (NOWAIT)
    JOIN sys.types tp WITH (NOWAIT) ON c.user_type_id = tp.user_type_id
    LEFT JOIN sys.computed_columns cc WITH (NOWAIT) ON c.[object_id] = cc.[object_id] AND c.column_id = cc.column_id
    LEFT JOIN sys.default_constraints dc WITH (NOWAIT) ON c.default_object_id != 0 AND c.[object_id] = dc.parent_object_id AND c.column_id = dc.parent_column_id
    LEFT JOIN sys.identity_columns ic WITH (NOWAIT) ON c.is_identity = 1 AND c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
    WHERE c.[object_id] = @object_id
    ORDER BY c.column_id
    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, CHAR(9) + ' ')
    + ISNULL((SELECT CHAR(9) + ', CONSTRAINT [' + k.name + '] PRIMARY KEY (' +
                    (SELECT STUFF((
                         SELECT ', [' + c.name + '] ' + CASE WHEN ic.is_descending_key = 1 THEN 'DESC' ELSE 'ASC' END
                         FROM sys.index_columns ic WITH (NOWAIT)
                         JOIN sys.columns c WITH (NOWAIT) ON c.[object_id] = ic.[object_id] AND c.column_id = ic.column_id
                      WHERE ic.is_included_column = 0
                             AND ic.[object_id] = k.parent_object_id
                             AND ic.index_id = k.unique_index_id
                         FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, ''))
            + ')' + CHAR(13)
            FROM sys.key_constraints k WITH (NOWAIT)
            WHERE k.parent_object_id = @object_id
                AND k.[type] = 'PK'), '') + ')'  + CHAR(13)
    + ISNULL((SELECT (
        SELECT CHAR(13) +
             'ALTER TABLE ' + @object_name + ' WITH'
            + CASE WHEN fk.is_not_trusted = 1
                THEN ' NOCHECK'
                ELSE ' CHECK'
              END +
              ' ADD CONSTRAINT [' + fk.name  + '] FOREIGN KEY('
              + STUFF((
                SELECT ', [' + k.cname + ']'
                FROM fk_columns k
                WHERE k.constraint_object_id = fk.[object_id]
                FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
               + ')' +
              ' REFERENCES [' + SCHEMA_NAME(ro.[schema_id]) + '].[' + ro.name + '] ('
              + STUFF((
                SELECT ', [' + k.rcname + ']'
                FROM fk_columns k
                WHERE k.constraint_object_id = fk.[object_id]
                FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '')
               + ')'
            + CASE
                WHEN fk.delete_referential_action = 1 THEN ' ON DELETE CASCADE'
                WHEN fk.delete_referential_action = 2 THEN ' ON DELETE SET NULL'
                WHEN fk.delete_referential_action = 3 THEN ' ON DELETE SET DEFAULT'
                ELSE ''
              END
            + CASE
                WHEN fk.update_referential_action = 1 THEN ' ON UPDATE CASCADE'
                WHEN fk.update_referential_action = 2 THEN ' ON UPDATE SET NULL'
                WHEN fk.update_referential_action = 3 THEN ' ON UPDATE SET DEFAULT'
                ELSE ''
              END
            + CHAR(13) + 'ALTER TABLE ' + @object_name + ' CHECK CONSTRAINT [' + fk.name  + ']' + CHAR(13)
        FROM sys.foreign_keys fk WITH (NOWAIT)
        JOIN sys.objects ro WITH (NOWAIT) ON ro.[object_id] = fk.referenced_object_id
        WHERE fk.parent_object_id = @object_id
        FOR XML PATH(N''), TYPE).value('.', 'NVARCHAR(MAX)')), '')
    + ISNULL(((SELECT
         CHAR(13) + 'CREATE' + CASE WHEN i.is_unique = 1 THEN ' UNIQUE' ELSE '' END
                + ' NONCLUSTERED INDEX [' + i.name + '] ON ' + @object_name + ' (' +
                STUFF((
                SELECT ', [' + c.name + ']' + CASE WHEN c.is_descending_key = 1 THEN ' DESC' ELSE ' ASC' END
                FROM index_column c
                WHERE c.is_included_column = 0
                    AND c.index_id = i.index_id
                FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')'
                + ISNULL(CHAR(13) + 'INCLUDE (' +
                    STUFF((
                    SELECT ', [' + c.name + ']'
                    FROM index_column c
                    WHERE c.is_included_column = 1
                        AND c.index_id = i.index_id
                    FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 2, '') + ')', '')  + CHAR(13)
        FROM sys.indexes i WITH (NOWAIT)
        WHERE i.[object_id] = @object_id
            AND i.is_primary_key = 0
            AND i.[type] = 2
        FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
    ), '')

PRINT @SQL
--EXEC sys.sp_executesql @SQL
END


1 2 3 4 5 6