저장 프로 시저의 결과 세트에서 열을 선택하십시오.


448

80 열과 300 행을 반환하는 저장 프로 시저가 있습니다. 해당 열 중 2 개를 가져 오는 선택을 작성하고 싶습니다. 같은 것

SELECT col1, col2 FROM EXEC MyStoredProc 'param1', 'param2'

위의 구문을 사용하면 오류가 발생합니다.

"잘못된 열 이름".

가장 쉬운 해결책은 저장 프로 시저를 변경하는 것이지만 작성하지 않았으며 변경할 수 없습니다.

내가 원하는 것을 할 수있는 방법이 있습니까?

  • 결과를 넣을 임시 테이블을 만들 수는 있지만 80 개의 열이 있으므로 2 열을 얻으려면 80 열 임시 테이블을 만들어야합니다. 반환 된 모든 열을 추적하지 않으려 고했습니다.

  • WITH SprocResults AS ....Mark가 제안한대로 사용하려고했지만 2 오류가 발생했습니다.

    키워드 'EXEC'근처의 구문이 잘못되었습니다.
    ')'근처의 구문이 잘못되었습니다.

  • 테이블 변수를 선언하려고했는데 다음 오류가 발생했습니다.

    삽입 오류 : 열 이름 또는 제공된 값 수가 테이블 정의와 일치하지 않습니다

  • 시도
    SELECT * FROM EXEC MyStoredProc 'param1', 'param2'
    하면 오류가 발생합니다.

    키워드 'exec'근처의 구문이 잘못되었습니다.


호기심에서이 쿼리는 작동합니까? SELECT * FROM EXEC MyStoredProc 'param1', 'param2'그렇다면 결과 세트에 표시되는 열 이름은 무엇이며 선택 목록에서 해당 열 이름을 사용할 수 있습니까?
Dave Costa

5
나는 이것에 대한 답을 찾지 못했습니다.
Rossini

32
글쎄, 당신은 매우 중요한 질문에 대답하지 않았습니다! 어떤 SQL 플랫폼을 요구하십니까? MySQL, Microsoft SQL Server, Oracle 등. SQL Server처럼 보이지만 사람들에게 말해야하거나 질문에 안정적으로 대답 할 수 없습니다.
JMTyler

6
MS-SQL이어야합니다. EXECMySQL 키워드가 아닙니다 (MySQL에 해당하는 준비되어 있습니다 ). MySQL에 대한 답변을 알고 싶지만 아래 답변은 T-SQL을 대상으로합니다. 태그 재 지정
bobobobo 2016 년

1
나는 이것에 대한 답을 찾지 못했다
Rossini

답변:


186

쿼리를 분할 할 수 있습니까? 저장된 proc 결과를 테이블 변수 또는 임시 테이블에 삽입하십시오. 그런 다음 테이블 변수에서 2 개의 열을 선택하십시오.

Declare @tablevar table(col1 col1Type,..
insert into @tablevar(col1,..) exec MyStoredProc 'param1', 'param2'

SELECT col1, col2 FROM @tablevar

27
또한 테이블 정의를 모르면 작동하지 않습니다
Ian Boyd

그 유형에 대해 몰랐습니다. 임시 테이블과 동일하게 구현 되었습니까? 아니면 엄격히 기억에 있습니까?
d -_- b

이것은 흥미 있었다 : sqlnerd.blogspot.com/2005/09/…
d -_- b

임시 테이블에 제공된 열 수가 저장 프로 시저 출력의 열 수와 동일한 경우에는 정상적으로 작동합니다. 채 버트.
Chagbert

83

다음은 문제를 해결하는 다양한 방법을 모두 설명하는 아주 좋은 문서에 대한 링크입니다 (기존 저장 프로 시저를 수정할 수 없으므로 많은 방법을 사용할 수는 없지만).

저장 프로 시저간에 데이터를 공유하는 방법

Gulzar의 대답은 효과가 있지만 (위의 링크에 문서화되어 있음) 작성하기가 번거로울 것입니다 (@tablevar (col1, ...) 문에 80 개의 열 이름을 모두 지정해야합니다. 열이 스키마에 추가되거나 출력이 변경되면 코드에서 업데이트해야합니다. 그렇지 않으면 오류가 발생합니다.


1
그 링크의 OPENQUERY 제안은 OP가 찾고있는 것에 훨씬 가깝다고 생각합니다.
코린


39

이것은 나를 위해 작동합니다 : (예 :에서 반환 된 30+ 중 2 열 만 필요합니다 sp_help_job)

SELECT name, current_execution_status 
FROM OPENQUERY (MYSERVER, 
  'EXEC msdb.dbo.sp_help_job @job_name = ''My Job'', @job_aspect = ''JOB''');  

이것이 작동하기 전에 이것을 실행해야했습니다.

sp_serveroption 'MYSERVER', 'DATA ACCESS', TRUE;

.... sys.servers테이블 을 업데이트 합니다. (즉, OPENQUERY 내에서 자체 참조 사용은 기본적으로 비활성화되어있는 것 같습니다.)

간단한 요구 사항에 대해서는 Lance의 우수한 링크의 OPENQUERY 섹션 에 설명 된 문제가 발생하지 않았습니다 .

Rossini, 이러한 입력 매개 변수를 동적으로 설정해야하는 경우 OPENQUERY 사용이 조금 더 어려워집니다.

DECLARE @innerSql varchar(1000);
DECLARE @outerSql varchar(1000);

-- Set up the original stored proc definition.
SET @innerSql = 
'EXEC msdb.dbo.sp_help_job @job_name = '''+@param1+''', @job_aspect = N'''+@param2+'''' ;

-- Handle quotes.
SET @innerSql = REPLACE(@innerSql, '''', '''''');

-- Set up the OPENQUERY definition.
SET @outerSql = 
'SELECT name, current_execution_status 
FROM OPENQUERY (MYSERVER, ''' + @innerSql + ''');';

-- Execute.
EXEC (@outerSql);

sp_serveroption기존 sys.servers자체 참조를 직접 업데이트하는 데 사용 하는 sp_addlinkedserver것과 Lance의 링크에 설명 된대로 사용하여 중복 / 별칭을 만드는 것의 차이점 (있는 경우)을 확신하지 못합니다 .

참고 1 : OPENQUERY가 proc 내에서 연결 문자열 정의를 요구하지 않는다는 점에서 OPENROWSET보다 OPENQUERY를 선호합니다.

주 2 : :) 네, 10 분 추가 입력,하지만 그것을 도울 수 있다면, 나는 주변에 소형 어선 안함 보통 그냥 INSERT ... EXEC을 사용 :이 모든 것을 말해 두 겠는데
따옴표 내에서의 (a) 따옴표 내 따옴표 및
(b) sys 테이블 및 / 또는 부적절한 자체 참조 링크 된 서버 설정 (즉,이 경우 모든 강력한 DBA에게 사례를 요구해야합니다.)

그러나이 인스턴스에서는 sp_help_job이미 INSERT ... EXEC 구문을 사용할 수 없었습니다 . ( "INSERT EXEC 문은 중첩 될 수 없습니다."


3
dynamic-sql-that-generated-dynamic-sql-that-generated-dynamic-sql에서 이전에 13 개의 작은 따옴표가있었습니다.
ErikE

작업이 완료되었는지 확인해야합니다. "INSERT EXEC 문을 중첩 할 수 없습니다." 나는 당신을 Microsoft 싫어.
alexkovelsky

11

이를 달성하려면 먼저 다음 #test_table과 같이 작성하십시오 .

create table #test_table(
    col1 int,
    col2 int,
   .
   .
   .
    col80 int
)

이제 프로 시저를 실행하고 값을 입력하십시오 #test_table.

insert into #test_table
EXEC MyStoredProc 'param1', 'param2'

이제 다음에서 값을 가져옵니다 #test_table.

select col1,col2....,col80 from #test_table

2
테이블 변수 대신 임시 테이블을 작성하면 이점이 있습니까?
Dave Kelly

1
내가 stackoverflow에서 찾은 최고의 솔루션! :)
Umar

4
다른 저장 프로 시저에서 하나의 열만 필요한 경우 어떻게합니까?
Keval Patel

11

저장 프로 시저를 수정할 수 있으면 필요한 열 정의를 매개 변수로 쉽게 넣고 자동 생성 된 임시 테이블을 사용할 수 있습니다.

CREATE PROCEDURE sp_GetDiffDataExample
      @columnsStatement NVARCHAR(MAX) -- required columns statement (e.g. "field1, field2")
AS
BEGIN
    DECLARE @query NVARCHAR(MAX)
    SET @query = N'SELECT ' + @columnsStatement + N' INTO ##TempTable FROM dbo.TestTable'
    EXEC sp_executeSql @query
    SELECT * FROM ##TempTable
    DROP TABLE ##TempTable
END

이 경우 임시 테이블을 수동으로 만들 필요가 없습니다. 자동으로 생성됩니다. 도움이 되었기를 바랍니다.


## 테이블은 세션간에 공유되므로주의하십시오
eKelvin


이 SQL 주입 경향이 있습니까?
Bushrod

11

이것이 왜 어려운지 아는 것이 도움이 될 수 있습니다. 저장 프로시 저는 텍스트 (인쇄 'text') 만 반환하거나 여러 테이블을 반환하거나 테이블을 전혀 반환하지 않을 수 있습니다.

그래서 SELECT * FROM (exec sp_tables) Table1 작동하지 않을 것입니다


12
이런 상황이 발생하면 SQL Server는 오류를 자유롭게 발생시킵니다. 예를 들어 둘 이상의 값을 반환하는 하위 쿼리를 작성하는 경우. 네, 그것은 수있는 일이 있지만, 실제로는 그렇지 않습니다. 그렇더라도 오류를 발생시키는 것은 어렵지 않습니다.
Ian Boyd

8

(SQL 서버 가정)

T-SQL에서 저장 프로 시저 결과를 처리 할 수있는 유일한 방법은 INSERT INTO ... EXEC구문 을 사용하는 것 입니다. 이를 통해 임시 테이블 또는 테이블 변수에 삽입하고 필요한 데이터를 선택할 수 있습니다.


1
이를 위해서는 테이블 정의를 알아야합니다. 유용하지 않다.
Triynko

8

빠른 해킹은 새 매개 변수를 추가 '@Column_Name'하고 호출 함수가 검색 할 열 이름을 정의하도록하는 것입니다. sproc의 반환 부분에는 if / else 문이 있고 지정된 열만 반환하거나 비어있는 경우 모두 반환합니다.

CREATE PROCEDURE [dbo].[MySproc]
        @Column_Name AS VARCHAR(50)
AS
BEGIN
    IF (@Column_Name = 'ColumnName1')
        BEGIN
            SELECT @ColumnItem1 as 'ColumnName1'
        END
    ELSE
        BEGIN
            SELECT @ColumnItem1 as 'ColumnName1', @ColumnItem2 as 'ColumnName2', @ColumnItem3 as 'ColumnName3'
        END
END

7

데이터의 수동 유효성 검사를 위해이 작업을 수행하는 경우 LINQPad를 사용하여이 작업을 수행 할 수 있습니다.

LinqPad에서 데이터베이스에 대한 연결을 작성한 후 다음과 유사한 C # 명령문을 작성하십시오.

DataTable table = MyStoredProc (param1, param2).Tables[0];
(from row in table.AsEnumerable()
 select new
 {
  Col1 = row.Field<string>("col1"),
  Col2 = row.Field<string>("col2"),
 }).Dump();

참조 http://www.global-webnet.net/blogengine/post/2008/09/10/LINQPAD-Using-Stored-Procedures-Accessing-a-DataSet.aspx


7

SQL Server의 경우 이것이 잘 작동한다는 것을 알았습니다.

임시 테이블 (또는 영구 테이블은 중요하지 않음)을 만들고 저장 프로 시저에 대해 insert into 문을 수행하십시오. SP의 결과 집합이 테이블의 열과 일치해야합니다. 그렇지 않으면 오류가 발생합니다.

예를 들면 다음과 같습니다.

DECLARE @temp TABLE (firstname NVARCHAR(30), lastname nvarchar(50));

INSERT INTO @temp EXEC dbo.GetPersonName @param1,@param2;
-- assumption is that dbo.GetPersonName returns a table with firstname / lastname columns

SELECT * FROM @temp;

그게 다야!


이를 위해 테이블 ​​정의 사본을 작성해야합니다. 피할 수있는 방법이 있습니까?
Hardik

7

질문에서 언급했듯이 저장 프로 시저를 실행하기 전에 80 열 임시 테이블을 정의하기가 어렵습니다.

따라서이 문제를 해결하는 다른 방법은 저장 프로 시저 결과 집합을 기반으로 테이블을 채우는 것입니다.

SELECT * INTO #temp FROM OPENROWSET('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;'
                                   ,'EXEC MyStoredProc')

오류가 발생하면 다음 쿼리를 실행하여 임시 분산 쿼리를 활성화해야합니다.

sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

sp_configure두 매개 변수로 실행 하여 구성 옵션을 변경하거나 RECONFIGURE명령문 을 실행 하려면 ALTER SETTINGS서버 레벨 권한 이 부여되어야합니다.

이제 생성 된 테이블에서 특정 열을 선택할 수 있습니다

SELECT col1, col2
FROM #temp

4

이 시도

use mydatabase
create procedure sp_onetwothree as
select 1 as '1', 2 as '2', 3 as '3'
go
SELECT a.[1], a.[2]
FROM OPENROWSET('SQLOLEDB','myserver';'sa';'mysapass',
    'exec mydatabase.dbo.sp_onetwothree') AS a
GO

1
롤-그는하지 않았다. 그는 네트워크 스니핑으로 데이터베이스에 액세스하지 않고도 훨씬 쉽게 얻을 수있는 저장 프로 시저를 호출하도록 코드화했습니다.
Martin Milan

Github에서도 쉽게 얻을 수 있습니다.
nomen

3

sp에서 삽입하고 임시 테이블 또는 테이블 변수에 삽입하는 것이 옵션 일 것입니다.하지만 이것이 귀하의 요구 사항이라고 생각하지 않습니다. 귀하의 요구 사항에 따라 아래 쿼리 문이 작동해야합니다.

Declare @sql nvarchar(max)
Set @sql='SELECT   col1, col2 FROM OPENROWSET(''SQLNCLI'', ''Server=(local);uid=test;pwd=test'',
     ''EXEC MyStoredProc ''''param1'''', ''''param2'''''')'
 Exec(@sql)

신뢰할 수있는 연결이 있다면 아래 쿼리 문을 사용하십시오.

Declare @sql nvarchar(max)
Set @sql='SELECT   col1, col2 FROM OPENROWSET(''SQLNCLI'', ''Server=(local);Trusted_Connection=yes;'',
     ''EXEC MyStoredProc ''''param1'''', ''''param2'''''')'
 Exec(@sql)

위의 명령문을 실행하는 데 오류가 발생하면 아래 명령문을 실행하십시오.

sp_configure 'Show Advanced Options', 1
GO
RECONFIGURE
GO
sp_configure 'Ad Hoc Distributed Queries', 1
GO
RECONFIGURE
GO

나는 이것이 이런 종류의 비슷한 문제에 직면했을 누군가를 도울 수 있기를 바랍니다. 누군가 아래의 이와 같은 임시 테이블 또는 테이블 변수를 사용하려고 시도하지만이 시나리오에서 sp가 얼마나 많은 열을 반환하는지 알고 있어야하는 경우 임시 테이블 또는 테이블 변수에 많은 열을 만들어야합니다.

--for table variable 
Declare @t table(col1 col1Type, col2 col2Type)
insert into @t exec MyStoredProc 'param1', 'param2'
SELECT col1, col2 FROM @t

--for temp table
create table #t(col1 col1Type, col2 col2Type)
insert into #t exec MyStoredProc 'param1', 'param2'
SELECT col1, col2 FROM #t

1

SQL 2012 이상을 가진 사람은 동적이지 않고 매번 동일한 열이 출력되는 저장 프로 시저를 사용하여이 작업을 수행 할 수있었습니다.

일반적인 아이디어는 동적 테이블을 작성하여 임시 테이블을 작성, 삽입, 선택 및 삭제하고 생성 된 후에 실행하는 것입니다. 먼저 저장 프로 시저에서 열 이름과 형식을 검색 하여 임시 테이블을 동적으로 생성합니다 .

참고 : SP를 업데이트하거나 구성을 변경하고 사용하고자하는 경우 더 적은 수의 코드로 작동하는 훨씬 더 우수하고 보편적 인 솔루션이 있습니다 OPENROWSET. 다른 방법이 없으면 아래를 사용하십시오.

DECLARE @spName VARCHAR(MAX) = 'MyStoredProc'
DECLARE @tempTableName VARCHAR(MAX) = '#tempTable'

-- might need to update this if your param value is a string and you need to escape quotes
DECLARE @insertCommand VARCHAR(MAX) = 'INSERT INTO ' + @tempTableName + ' EXEC MyStoredProc @param=value'

DECLARE @createTableCommand VARCHAR(MAX)

-- update this to select the columns you want
DECLARE @selectCommand VARCHAR(MAX) = 'SELECT col1, col2 FROM ' + @tempTableName

DECLARE @dropCommand VARCHAR(MAX) = 'DROP TABLE ' + @tempTableName

-- Generate command to create temp table
SELECT @createTableCommand = 'CREATE TABLE ' + @tempTableName + ' (' +
    STUFF
    (
        (
            SELECT ', ' + CONCAT('[', name, ']', ' ', system_type_name)
            FROM sys.dm_exec_describe_first_result_set_for_object
            (
              OBJECT_ID(@spName), 
              NULL
            )
            FOR XML PATH('')
        )
        ,1
        ,1
        ,''
    ) + ')'

EXEC( @createTableCommand + ' '+ @insertCommand + ' ' + @selectCommand + ' ' + @dropCommand)

0

한 번만 필요한 경우 가장 쉬운 방법 :

가져 오기 및 내보내기 마법사에서 Excel로 내보내기를 한 다음이 Excel을 테이블로 가져옵니다.


4
스토어드 프로 시저를 작성하는 요점은 재사용 성입니다. 당신의 대답은 전적으로 모순됩니다.
deutschZuid

6
원래 게시물에서 deutschZuid에 대항하기 위해, 그는 이것을 재사용하고 싶은지 아닌지 또는 그가 저장된 proc의 결과를 조사하려고하는지 언급하지 않습니다. 마틴이 맞습니다. 아마도 한 번만 수행하면 가장 쉬운 방법 일 것입니다.
주교

0

동적 뷰를 생성하고 그 결과를 얻습니다 .......

CREATE PROCEDURE dbo.usp_userwise_columns_value
(
    @userid BIGINT
)
AS 
BEGIN
        DECLARE @maincmd NVARCHAR(max);
        DECLARE @columnlist NVARCHAR(max);
        DECLARE @columnname VARCHAR(150);
        DECLARE @nickname VARCHAR(50);

        SET @maincmd = '';
        SET @columnname = '';
        SET @columnlist = '';
        SET @nickname = '';

        DECLARE CUR_COLUMNLIST CURSOR FAST_FORWARD
        FOR
            SELECT columnname , nickname
            FROM dbo.v_userwise_columns 
            WHERE userid = @userid

        OPEN CUR_COLUMNLIST
        IF @@ERROR <> 0
            BEGIN
                ROLLBACK
                RETURN
            END   

        FETCH NEXT FROM CUR_COLUMNLIST
        INTO @columnname, @nickname

        WHILE @@FETCH_STATUS = 0
            BEGIN
                SET @columnlist = @columnlist + @columnname + ','

                FETCH NEXT FROM CUR_COLUMNLIST
                INTO @columnname, @nickname
            END
        CLOSE CUR_COLUMNLIST
        DEALLOCATE CUR_COLUMNLIST  

        IF NOT EXISTS (SELECT * FROM sys.views WHERE name = 'v_userwise_columns_value')
            BEGIN
                SET @maincmd = 'CREATE VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), @userid) + ') as userid , ' 
                            + CHAR(39) + @nickname + CHAR(39) + ' as nickname, ' 
                            + @columnlist + ' compcode FROM dbo.SJOTran '
            END
        ELSE
            BEGIN
                SET @maincmd = 'ALTER VIEW dbo.v_userwise_columns_value AS SELECT sjoid, CONVERT(BIGINT, ' + CONVERT(VARCHAR(10), @userid) + ') as userid , ' 
                            + CHAR(39) + @nickname + CHAR(39) + ' as nickname, ' 
                            + @columnlist + ' compcode FROM dbo.SJOTran '
            END

        --PRINT @maincmd
        EXECUTE sp_executesql @maincmd
END

-----------------------------------------------
SELECT * FROM dbo.v_userwise_columns_value

-1

원래 SP를 잘라 붙여 넣고 원하는 2를 제외한 모든 열을 삭제했습니다. 또는. 결과 집합을 다시 가져 와서 적절한 비즈니스 개체에 매핑 한 다음 두 열을 LINQ합니다.


1
사람들은 이것을하지 않습니다. 이것은 드라이 원칙을 위반합니다. 상황이 바뀌더라도 변경되지 않으면 이제 모든 위치에서 변경 사항을 추적하고 입력해야합니다.
jriver27
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.