달력

4

« 2024/4 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
2019. 7. 11. 14:40

Microsoft SQL Server, 오류: 15023 Work/SQL Server2019. 7. 11. 14:40

SQL Server에서 백업 후 다른 인스턴스로 복구한 데이터베이스에 계정을 생성시 발생하는 오류...

해당 데이터베이스 에서 아래처럼 실행하면, 해결됨

 

exec sp_change_users_login 'UPDATE_ONE', '사용자명', '로그인명'

 

ex)

exec sp_change_users_login 'UPDATE_ONE', 'uae', 'uae'

 

간단해서 좋으네...

:
Posted by Elick
2012. 4. 10. 19:05

SQL Server 배열형 매개변수 처리 Work/SQL Server2012. 4. 10. 19:05

개발을 하다 보면 1차원 배열을 받아서 테이블 형태로 가공한 뒤 처리해야 할 경우가 발생한다.

이를 처리하는 방법에 대한 정리.


Method 1: Dynamic SQL


CREATE PROC dbo.GetOrderList1

(

@OrderList varchar(500)

)

AS

BEGIN

SET NOCOUNT ON


DECLARE @SQL varchar(600)


SET @SQL = 

'SELECT OrderID, CustomerID, EmployeeID, OrderDate

FROM dbo.Orders

WHERE OrderID IN (' + @OrderList + ')'


EXEC(@SQL)

END

GO


EXEC dbo.GetOrderList1 '10248,10252,10256,10261,10262,10263,10264,10265,10300,10311'

GO


Method 2: Pass...


Method 3: Parsing the comma separated values into a table variable and joining the table variable to main table


CREATE PROC dbo.GetOrderList3

(

@OrderList varchar(500)

)

AS

BEGIN

SET NOCOUNT ON


DECLARE @TempList table

(

OrderID int

)


DECLARE @OrderID varchar(10), @Pos int


SET @OrderList = LTRIM(RTRIM(@OrderList))+ ','

SET @Pos = CHARINDEX(',', @OrderList, 1)


IF REPLACE(@OrderList, ',', '') <> ''

BEGIN

WHILE @Pos > 0

BEGIN

SET @OrderID = LTRIM(RTRIM(LEFT(@OrderList, @Pos - 1)))

IF @OrderID <> ''

BEGIN

INSERT INTO @TempList (OrderID) VALUES (CAST(@OrderID AS int)) --Use Appropriate conversion

END

SET @OrderList = RIGHT(@OrderList, LEN(@OrderList) - @Pos)

SET @Pos = CHARINDEX(',', @OrderList, 1)


END

END


SELECT o.OrderID, CustomerID, EmployeeID, OrderDate

FROM dbo.Orders AS o

JOIN 

@TempList t

ON o.OrderID = t.OrderID

END

GO


EXEC dbo.GetOrderList3 '10248,10252,10256,10261,10262,10263,10264,10265,10300,10311'

GO



Method 4: Using XML


CREATE PROC dbo.GetOrderList4

(

@OrderList varchar(1000)

)

AS

BEGIN

SET NOCOUNT ON


DECLARE @DocHandle int


EXEC sp_xml_preparedocument @DocHandle OUTPUT, @OrderList


SELECT o.OrderID, CustomerID, EmployeeID, OrderDate

FROM dbo.Orders AS o

JOIN

OPENXML (@DocHandle, '/ROOT/Ord',1) WITH (OrderID  int) AS x

ON o.OrderID = x.OrderID


EXEC sp_xml_removedocument @DocHandle 

END

GO


EXEC dbo.GetOrderList4 '

<ROOT>

<Ord OrderID = "10248"/> <Ord OrderID = "10252"/>

<Ord OrderID = "10256"/> <Ord OrderID = "10261"/>

<Ord OrderID = "10262"/> <Ord OrderID = "10263"/>

<Ord OrderID = "10264"/> <Ord OrderID = "10265"/>

<Ord OrderID = "10300"/> <Ord OrderID = "10311"/>

<Ord OrderID = "11068"/> <Ord OrderID = "11069"/>

<Ord OrderID = "11070"/> <Ord OrderID = "11071"/>

<Ord OrderID = "11072"/> <Ord OrderID = "11073"/>

<Ord OrderID = "11074"/> <Ord OrderID = "11075"/>

<Ord OrderID = "11076"/> <Ord OrderID = "11077"/>

</ROOT>'

GO



Method 5: Using a table of numbers or pivot table, to parse the comma separated list


--Create a table called Numbers

CREATE TABLE dbo.Numbers

(

Number int PRIMARY KEY CLUSTERED

)

GO


--Insert 8000 numbers into this table (from 1 to 8000)

SET NOCOUNT ON

GO


DECLARE @CTR int

SET @CTR = 1

WHILE @CTR < 8001

BEGIN

INSERT INTO dbo.Numbers (Number) VALUES (@CTR)

SET @CTR = @CTR + 1

END

GO

--The above two steps are to be run only once. The following stored procedure uses the number table.


CREATE PROC dbo.GetOrderList5

(

@OrderList varchar(1000)

)

AS

BEGIN

SET NOCOUNT ON


SELECT o.OrderID, CustomerID, EmployeeID, OrderDate

FROM dbo.Orders AS o

JOIN

(

SELECT LTRIM(RTRIM(SUBSTRING(OrderID, number+1, CHARINDEX(',', OrderID, number+1)-number - 1))) AS OrderID

FROM

(

SELECT ',' + @OrderList + ',' AS OrderID

) AS InnerQuery

JOIN 

Numbers n 

ON 

n.Number < LEN(InnerQuery.OrderID)

WHERE SUBSTRING(OrderID, number, 1) = ','

) as Derived

ON o.OrderID = Derived.OrderID


END

GO


EXEC dbo.GetOrderList5 '10248,10252,10256,10261,10262,10263,10264,10265,10300,10311'

GO


Method 6: Using a general purpose User Defined Function (UDF) to parse the comma separated OrderIDs


--The following is a general purpose UDF to split comma separated lists into individual items.

--Consider an additional input parameter for the delimiter, so that you can use any delimiter you like.

CREATE FUNCTION dbo.SplitOrderIDs

(

@OrderList varchar(500)

)

RETURNS 

@ParsedList table

(

OrderID int

)

AS

BEGIN

DECLARE @OrderID varchar(10), @Pos int


SET @OrderList = LTRIM(RTRIM(@OrderList))+ ','

SET @Pos = CHARINDEX(',', @OrderList, 1)


IF REPLACE(@OrderList, ',', '') <> ''

BEGIN

WHILE @Pos > 0

BEGIN

SET @OrderID = LTRIM(RTRIM(LEFT(@OrderList, @Pos - 1)))

IF @OrderID <> ''

BEGIN

INSERT INTO @ParsedList (OrderID) 

VALUES (CAST(@OrderID AS int)) --Use Appropriate conversion

END

SET @OrderList = RIGHT(@OrderList, LEN(@OrderList) - @Pos)

SET @Pos = CHARINDEX(',', @OrderList, 1)


END

END

RETURN

END

GO


CREATE PROC dbo.GetOrderList6

(

@OrderList varchar(500)

)

AS

BEGIN

SET NOCOUNT ON

SELECT o.OrderID, CustomerID, EmployeeID, OrderDate

FROM dbo.Orders AS o

JOIN

dbo.SplitOrderIDs(@OrderList) AS s

ON

o.OrderID = s.OrderID

END

GO


EXEC dbo.GetOrderList6 '10248,10252,10256,10261,10262,10263,10264,10265,10300,10311'

GO


Best Solution (최상의 성능과 간단한 구현)

: 천재다...

DECLARE @textXML XML

DECLARE @data NVARCHAR(MAX), 

        @delimiter NVARCHAR(5)


SELECT  @data = 'A,B,C',

        @delimiter = ','


SELECT    @textXML = CAST('<d>' + REPLACE(@data, @delimiter, '</d><d>') + '</d>' AS XML)

SELECT  T.split.value('.', 'nvarchar(max)') AS data

FROM    @textXML.nodes('/d') T(split)


참고 URL

http://vyaskn.tripod.com/passing_arrays_to_stored_procedures.htm

http://stackoverflow.com/questions/1922191/passing-array-as-parameter-to-sql-2005-stored-procedure


:
Posted by Elick
2012. 4. 9. 15:56

SQL Server Linked Server 쿼리 활용 Work/SQL Server2012. 4. 9. 15:56

SQL Server로 Linked Query를 사용하여 작업할 경우가 많다.

Linked Query 자체를 생성하는 것이 힘겨운 경우도 있고... 우여곡절이 많다. ㅠㅠ


이번 기록은 Linked Query를 일단 생성한 후의 활용에 대해서 정리한다.


Query

: SELECT * FROM <Linked Server Name>..<Owner Name>.<Table Name> WHERE ~~;

-- 성능 않좋고... 어딘가에 써먹을 데가 별로 없다.

-- 쿼리 작성이 간단하다.

-- 4-Part 라고 한다.

-- INSERT, UPDATE, DELETE 문장을 보통 쿼리문과 비슷하게 사용한다.

: SELECT * FROM OPENQUERY(<Linked Server Name>, 'SELECT * FROM <Table Name> WHERE ~~');

-- 성능이 나쁘지 않고, 자주 사용.

-- 쿼리를 문자열로 조합하기 귀찮음.

-- OPENQUERY 라고 한다.

-- INSERT의 경우 OPENQUERY 내의 SELECT 문에 WHERE 1<>1 로 UPDATE, DELETE 문은 검색 제한자를 정확히 써서 인덱스를 잘 사용하면 성능이 봐줄만 하다.

-- OPENQUERY 내의 문자열은 완성된 형태의 문자열만 가능하며, 변수는 받을 수 없다. <-- 이게 치명적인 귀찮음...


Procedure 호출

: Oracle Procedure

execute ('call <OracleSchema>.<OracleProcedureName>()') at <Linked Server Name>

관련 link : http://social.msdn.microsoft.com/Forums/en-US/sqlsmoanddmo/thread/12e9c126-496b-49ad-9bf7-4320f7d09af8

: Oracle Package

SELECT *

FROM  OPENQUERY(ls_name , '{CALL  user1.upk_test.up_test_inpkg(1111,''222'', {resultSet 1, po_RecordSet }}');

"sqlServer에 linked server로 oracle에 연결하고, oracle의 sp를 call한 후, 응답코드에 따라
 이후 작업 진행"

위와 같은 방법보다는 application에서 control하는 것이 좋을 듯 하지만, 어쩔 수 없이 이렇게
해야만 하는 경우가 있어, 코드 부스러기 주워담아 아래와 같이 해결했다.

return값을 table형식이 아닌 number형식으로 받는 방법을 몰라서 응답코드를 table형식으로 return
하도록 처리하였다.(이에 대해서 좀 더 효율적인 방법에 대해서 댓글 부탁합니다.)

CASE1) oracle에서 package를 작성
1. oracle에서 패키지 작성
----------------------------------------------------------------
create or replace package upk_test
as
    type tbltype is table of number(10)
    index by pls_integer;

    procedure up_test_inpkg(
    pi_nParam1        IN  NUMBER,
    pi_szParam1       IN  VARCHAR2,

    po_RecordSet      OUT TblType
    );
end upk_test;
/

create or replace package body upk_test
as
    procedure up_test_inpkg(
    pi_nParam1        IN  NUMBER,
    pi_szParam1       IN  VARCHAR2,

    po_RecordSet      OUT TblType
    ) as
    begin

    /**
    business logic 구현
    ......
    **/
    
    --넘겨줄 처리결과 코드 세팅
    po_RecordSet(1) := v_nResult;

    end up_test_inpkg;
end upk_test;
----------------------------------------------------------------

2. sqlserver에서 openquery를 통해 query
----------------------------------------------------------------
SELECT *
FROM  OPENQUERY(ls_name , '{CALL  user1.upk_test.up_test_inpkg(1111,''222'', {resultSet 1, po_RecordSet }}');
----------------------------------------------------------------


CASE2) oracle에서 package에 type선언만 하고 해당 type을 sp에서 참조
----------------------------------------------------------------
create or replace package upk_types
as
    type numtbltype is table of number(10)
    index by pls_integer;
end upk_types;
/


create or replace procedure up_test(
    pi_nParam1        IN  NUMBER,
    pi_szParam1       IN  VARCHAR2,

    po_RecordSet      OUT upk_type.numtbltype
)
as
    
begin
    /**
    business logic 구현
    ......
    **/
    
    --넘겨줄 처리결과 코드 세팅
    po_RecordSet(1) := v_nResult;
end;

----------------------------------------------------------------

관련 link : http://dialup.egloos.com/927560


: PostgreSQL Procedure

SELECT * FROM OPENQUERY(<Linked Server Name>, 'SELECT * FROM <Procedure Name>');

:
Posted by Elick
2011. 12. 9. 13:36

SQL Server 난수 처리 Work/SQL Server2011. 12. 9. 13:36

구현 목적 : 테이블에서 결과를 가져온 결과셋에서 모든 row에 각기 다른 난수를 발생하게 한다.
구현 1차시도 실패 : SQL Server의 경우  실행시 마다 다른 난수 발생은 문제가 없으나, 결과셋의 row에 난수를 발생시키는 것은 상식적인 구현으로 처리가 안되었음. (Oralce의 경우는 간단한 구현으로 쉽게 됨.)

Oracle의 예 (Oracle 9i) 

SQL> SELECT TNAME, DBMS_RANDOM.value() rv FROM TAB WHERE rownum < 10;

TNAME                                                                RV
------------------------------------------------------------ ----------
APPHIS                                                       .227993266
APPIP                                                        .125859742
APPUSER                                                      .920119229
BIB                                                          .880236699
BIB1                                                         .249643606
BIB2                                                         .079614467
BIB3                                                         .762079535
BTIPC2                                                       .453071388
BTIPC_2                                                      .250049303

9 개의 행이 선택되었습니다.



SQL Server의 예 (SQL Server 2008 R2)

SELECT TOP 9 name, rand() RV FROM sys.objects;
name RV
-------------------------------------

sysrscols 0.374134079506195
sysrowsets 0.374134079506195
sysallocunits 0.374134079506195
sysfiles1 0.374134079506195
syspriorities 0.374134079506195
sysfgfrag 0.374134079506195
sysphfg 0.374134079506195
sysprufiles 0.374134079506195
sysftinds 0.374134079506195

(9개 행이 영향을 받음)

 

위에서 알 수 있듯이 난수 발생 결과 두 DBMS에서 상이하다. (이외에 난수 발생 구간을 설정하는 등에서 난수함수 사용성은 개인적으로 Oracle이 좀 더 편한 듯 하다. 이 부분에 대해서 SQL Server 로 비슷하게 구현하는 것을 목표로 한다.

CREATE VIEW dbo.V_RANDOM
AS
SELECT RAND() AS RN;
GO

CREATE FUNCTION dbo.uf_Random(@iStart int, @iEnd int)
RETURNS float
AS
BEGIN
  DECLARE @result float;
  
  SELECT @result = (@iEnd - @iStart) * RN + @iStart
  FROM dbo.V_RANDOM;

  SET @result = ROUND(@result, 2);
  
  RETURN(@result);
END;
GO

-- TEST
SELECT TOP 9
name, dbo.uf_Random(4, 5) RV
FROM sys.objects;

name RV
sysrscols 4.06
sysrowsets 4.37
sysallocunits 4.6
sysfiles1 4.83
syspriorities 4.03
sysfgfrag 4.43
sysphfg 4.53
sysprufiles 4.72
sysftinds 4.09 


참고글 : http://huhlog.tistory.com/9 
:
Posted by Elick
2011. 5. 26. 15:31

SQL Server PostgreSQL 연결된 서버 생성 Work/SQL Server2011. 5. 26. 15:31

OS / DBMS : Windows XP / SQL Server 2008 (32bit), CentOS 5.5 / PostgreSQL 9.0.3 (32bit)
위 상황에서 MSSQL Linked Server를 생성하는 작업을 하게 되었다.


 처음에는 공급자를 PostgreSQL OLE DB Provider 를 이용하여 연결을 시도했지만.... 연결 실패.

  ODBC를 이용하여 연결 시도.

PostgreSQL ODBC Driver를 Down 받고, 설치하고, Linked Server 를 생성하고... 연결테스트까지 성공.
    PostgreSQL ODBC Driver Download : http://www.postgresql.org/ftp/odbc/versions/msi/

OPENQUERY를 이용한 SELECT ... 실패

error message
--------------------------------
메시지 7399, 수준 16, 상태 1, 줄 1
연결된 서버 "xxxxx012"의 OLE DB 공급자 "MSDASQL"에 오류가 발생했습니다. 공급자에서 예기치 않은 치명적인 오류가 보고되었습니다.
메시지 7350, 수준 16, 상태 2, 줄 1
연결된 서버 "xxxxx012"의 OLE DB 공급자 "MSDASQL"에서 열 정보를 가져올 수 없습니다.
-------------------------------- 

원인은 64bit PostgreSQL을 Linked Server 생성할 경우 inprocess 허용을 uncheck 해야 한다.
참고 URL :  http://www.bisql.net/2011/02/sql_pg_linked/
inprocess 관련 내용 : http://manshei.tistory.com/94

정확한 원인은 모르겠지만... 어쨌든 SELECT 성공.

p.s.
sqler.com에 얼른 posting.. 그리고... blog에 기록.. 
쉽게 되는게 없구나....ㅠㅠ
:
Posted by Elick
2010. 12. 17. 11:14

Database Connection Strings Work/SQL Server2010. 12. 17. 11:14

항상 검색하던 건데...
어떤 천사분께서 정리해서 얼렁 퍼왔다.

-----------------------------
Database Connection Strings
1. OLEDB 연결 문자열
Microsoft SQL Server
Provider=SQLOLEDB;Data Source=db_server;Initial Catalog=database_name;User ID=user_id;Password=password

Oracle (MS Oracle OLEDB Provider)
Provider=MSDAORA.1;Data Source=oracle_tns_name;User ID=user_id;Password=password

Oracle (Oracle OLEDB Provider)
Provider=OraOLEDB.Oracle.1;Data Source=oracle_tns_name;User ID=user_id;Password=password

Microsoft Access
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.mdb 파일의 실제 경로

2. ODBC 연결 문자열
공통
DSN=data_source_name;UID=user_id;Pwd=password

Microsoft SQL Server
DRIVER={SQL Server};SERVER=db_server;UID=user_id;PWD=password;DATABASE=northwind

Microsoft SQL Server (MSDE)
DRIVER={SQL Server};SERVER=.\SQLEXPRESS;UID=user_id;PWD=password;DATABASE=northwind

Oracle
DRIVER={Microsoft ODBC for Oracle};SERVER=oracle_tns_name;UID=user_id;PWD=password

Microsoft Access
Driver={Microsoft Access Driver (*.mdb)};DBQ=.mdb 파일의 실제 경로

3. Oracle용 Microsoft ODBC Driver 와 OLEDB Provider 의 제약 사항
. Microsoft Data Access Components(MDAC) 버전 2.5 이상 버전부터 Microsoft ODBC 드라이버와 OLE DB 공급자는 모두 Oracle 8i를 지원하지만 다음과 같은 제한 사항이 갖고 있습니다.
. CLOB, BLOB, BFILE, NCHAR, NCLOB 및 NVARCHAR2 같은 Oracle 8.x 고유 데이터 형식은 지원되지 않습니다.
. Oracle 7.x 및 8.x 서버에 대한 유니코드 기능은 지원되지 않습니다. (10g 에서도 Microsoft ODBC 드라이버 사용시 유니코드 지원이 안되었음)
. 복수 Oracle 클라이언트 인스턴스나 복수 Oracle 홈은 SYSTEM PATH 변수에 나와 있는 Oracle 홈의 첫 번째 발생에 의존하므로 지원되지 않습니다.
. 저장 프로시저 또는 일괄 처리 SQL 문으로부터 여러 결과 집합을 반환할 때 ADO나 OLEDB를 사용할 수 없습니다.
. 단일 결과 집합 반환 시, OLEDB 에서는 프로시저에서 반환하는 REF CURSOR 를 지원하지만, ODBC 는 지원 안함
. 255043 (http://support.microsoft.com/kb/255043/) HOWTO: ASP를 통해 Oracle(REF CURSORS)에서 ADO 레코드 집합을 검색하는 방법
. 176086 (http://support.microsoft.com/kb/176086/) ADO를 사용하여 Oracle 저장 프로시저에서 레코드 집합을 검색하는 방법
. 중첩된 외부 조인은 지원되지 않습니다.
. XML 지속성은 지원되지 않습니다.
 

-----------------------------
출처 : http://blog.naver.com/dalbong97/130032211895

:
Posted by Elick
2010. 8. 27. 11:12

결과 셋을 Excel로 저장하기. Work/SQL Server2010. 8. 27. 11:12

예전에 찾은 자료인데... 가끔 써먹을 때도 있다.
경험상 결과셋을 굳이 Excel로 저장할 필요는 없다. BCP를 이용하여 CSV파일로 저장하면 되는데...
하여간 찾아놓은 고생이 아까워 기록은 해 두는 것이 좋을 듯...

사용할 수 있는 환경이 MSSQL의 보안 권고 사항과 충돌한다.
1. MSSQL 노출 영역 구성대상 / 기능에 대한 노출 영역 구성 / OLE 자동화 사용 : True
2. MSSQL 노출 영역 구성대상 / 기능에 대한 노출 영역 구성 / xp_cmdshell 사용 : True

/*
Version: SQL Server 7.0/2000
Created by: Alexander Chigrik
http://www.MSSQLCity.com/ - all about MS SQL
(SQL Server Articles, FAQ, Scripts, Tips and Test Exams).
This stored procedure can be used to insert the result set of the
particular select statement into Excel file (c:ImportToExcel.xls,
by default).
You can pass the server name, user name, user password, the select
statement to execute, and the file name to store the results set,
as in the example below:
EXEC ExportToExcel @server = '.',
                   @uname = 'sa',
                   @QueryText = 'SELECT au_fname FROM pubs..authors',
                   @filename = 'c:ImportToExcel.xls'
*/
IF OBJECT_ID('ExportToExcel') IS NOT NULL DROP PROC ExportToExcel
GO
CREATE PROCEDURE ExportToExcel (
  @server sysname = null,
  @uname sysname = null,
  @pwd sysname = null,
  @QueryText varchar(200) = null,
  @filename varchar(200) = 'c:ImportToExcel.xls'
)
AS
DECLARE @SQLServer int,
        @QueryResults int,
        @CurrentResultSet int,
        @object int,
        @WorkBooks int,
        @WorkBook int,
        @Range int,
        @hr int,
        @Columns int,
        @Rows int,
        @indColumn int,
        @indRow int,
        @off_Column int,
        @off_Row int,
        @code_str varchar(100),
        @result_str varchar(255)
IF @QueryText IS NULL
  BEGIN
    PRINT 'Set the query string'
    RETURN
  END
-- Sets the server to the local server
IF @server IS NULL SELECT @server = @@servername
-- Sets the username to the current user name
IF @uname IS NULL SELECT @uname = SYSTEM_USER
SET NOCOUNT ON
EXEC @hr = sp_OACreate 'SQLDMO.SQLServer', @SQLServer OUT
IF @hr <> 0
BEGIN
    PRINT 'error create SQLDMO.SQLServer'
    RETURN
END
--  Connect to the SQL Server
IF @pwd IS NULL
  BEGIN
    EXEC @hr = sp_OAMethod @SQLServer, 'Connect', null, @server, @uname
    IF @hr <> 0
       BEGIN
         PRINT 'error Connect'
         RETURN
       END
  END
ELSE
  BEGIN
    EXEC @hr = sp_OAMethod @SQLServer, 'Connect', null, @server, @uname, @pwd
    IF @hr <> 0
      BEGIN
        PRINT 'error Connect'
        RETURN
      END
  END
SELECT @result_str = 'ExecuteWithResults("' + @QueryText + '")'
EXEC @hr = sp_OAMethod @SQLServer, @result_str, @QueryResults OUT
IF @hr <> 0
BEGIN
    PRINT 'error with method ExecuteWithResults'
    RETURN
END
EXEC @hr = sp_OAMethod @QueryResults, 'CurrentResultSet', @CurrentResultSet OUT
IF @hr <> 0
BEGIN
    PRINT 'error get CurrentResultSet'
    RETURN
END
EXEC @hr = sp_OAMethod @QueryResults, 'Columns', @Columns OUT
IF @hr <> 0
BEGIN
    PRINT 'error get Columns'
    RETURN
END
EXEC @hr = sp_OAMethod @QueryResults, 'Rows', @Rows OUT
IF @hr <> 0
BEGIN
    PRINT 'error get Rows'
    RETURN
END
EXEC @hr = sp_OACreate 'Excel.Application', @object OUT
IF @hr <> 0
BEGIN
    PRINT 'error create Excel.Application'
    RETURN
END
EXEC @hr = sp_OAGetProperty @object, 'WorkBooks', @WorkBooks OUT
IF @hr <> 0
BEGIN
    PRINT 'error create WorkBooks'
    RETURN
END
EXEC @hr = sp_OAGetProperty @WorkBooks, 'Add', @WorkBook OUT
IF @hr <> 0
BEGIN
    PRINT 'error with method Add'
    RETURN
END
EXEC @hr = sp_OAGetProperty @object, 'Range("A1")', @Range OUT
IF @hr <> 0
BEGIN
    PRINT 'error create Range'
    RETURN
END
SELECT @indRow = 1
SELECT @off_Row = 0
SELECT @off_Column = 1
WHILE (@indRow <= @Rows)
BEGIN
SELECT @indColumn = 1
WHILE (@indColumn <= @Columns)
BEGIN
EXEC @hr = sp_OAMethod @QueryResults, 'GetColumnString', @result_str OUT, @indRow, @indColumn
IF @hr <> 0
BEGIN
    PRINT 'error get GetColumnString'
    RETURN
END
EXEC @hr = sp_OASetProperty @Range, 'Value', @result_str
IF @hr <> 0
BEGIN
    PRINT 'error set Value'
    RETURN
END
EXEC @hr = sp_OAGetProperty @Range, 'Offset', @Range OUT, @off_Row, @off_Column
IF @hr <> 0
BEGIN
    PRINT 'error get Offset'
    RETURN
END
SELECT @indColumn = @indColumn + 1
END
SELECT @indRow = @indRow + 1
SELECT @code_str = 'Range("A' + LTRIM(str(@indRow)) + '")'
EXEC @hr = sp_OAGetProperty @object, @code_str, @Range OUT
IF @hr <> 0
BEGIN
    PRINT 'error create Range'
    RETURN
END
END
SELECT @result_str = 'exec master..xp_cmdshell ''del ' + @filename + ''', no_output'
EXEC(@result_str)
SELECT @result_str = 'SaveAs("' + @filename + '")'
EXEC @hr = sp_OAMethod @WorkBook, @result_str
IF @hr <> 0
BEGIN
    PRINT 'error with method SaveAs'
    RETURN
END
EXEC @hr = sp_OAMethod @WorkBook, 'Close'
IF @hr <> 0
BEGIN
    PRINT 'error with method Close'
    RETURN
END
EXEC @hr = sp_OADestroy @object
IF @hr <> 0
BEGIN
    PRINT 'error destroy Excel.Application'
    RETURN
END
EXEC @hr = sp_OADestroy @SQLServer
IF @hr <> 0
BEGIN
    PRINT 'error destroy SQLDMO.SQLServer'
    RETURN
END
GO

--Version: SQL Server 7.0/2000
--Created by: Alexander Chigrik
--http://www.MSSQLCity.com/ - all about MS SQL
--(SQL Server Articles, FAQ, Scripts, Tips and Test Exams).
--
--This stored procedure can be used to insert the result set of the particular
--select statement into Excel file (c:ImportToExcel.xls, by default).
--You can pass the server name, user name, user password, the select statement
--to execute, and the file name to store the results set, as in the example below:

EXEC ExportToExcel @server = NULL,
                   @uname = 'xxxxxx',
                   @pwd = 'xxxxxxx',
                   @QueryText = 'SELECT * FROM dbXXX..tbXXX',
                   @filename = 'c:\xxxxx.xls'

:
Posted by Elick

Oracle 에서 사용했던 방법을 살짝 바꿨다.

나오는 결과에 비해서 쿼리가 길다. 어찌어찌하면 이쁘게 줄일 수도 있을 것 같은데... 너무 졸립다.
당연히 MSSQL 2005 이상부터 사용할 수 있을 듯..


WITH CTE (TNAME, CNAME, PRNUM, LEVEL) AS
(
SELECT convert(varchar(8000), TNAME) + '|', CNAME, PRNUM, 1 as LEVEL
FROM (
 SELECT object_name(object_id) TNAME
  , name CNAME
  , ROW_NUMBER () OVER (PARTITION BY name ORDER BY object_name(object_id)) PRNUM
 FROM sys.columns
 ) AA
WHERE PRNUM = 1
UNION ALL
SELECT CTE.TNAME + convert(varchar(8000), T.TNAME) + '|', T.CNAME, T.PRNUM, CTE.LEVEL + 1 LEVEL
FROM (
 SELECT object_name(object_id) TNAME
  , name CNAME
  , ROW_NUMBER () OVER (PARTITION BY name ORDER BY object_name(object_id)) PRNUM
 FROM sys.columns
 ) T INNER JOIN CTE ON CTE.PRNUM = (T.PRNUM - 1) AND T.CNAME = CTE.CNAME
WHERE T.PRNUM > 1
)
SELECT CTE.TNAME, CTE.CNAME, CTE.PRNUM
FROM CTE INNER JOIN (
SELECT CNAME, MAX(PRNUM) PRNUM
FROM (
 SELECT name CNAME
  , ROW_NUMBER () OVER (PARTITION BY name ORDER BY object_name(object_id)) PRNUM
 FROM sys.columns
 ) TA
GROUP BY CNAME) TABB ON CTE.CNAME = TABB.CNAME AND CTE.PRNUM = TABB.PRNUM;

Oracle의 SYS_CONNECT_BY_PATH  함수 같은거 쓸 수 있으면 좋을 거 같은데.. 찾아보기 너무 귀찮다.
:
Posted by Elick