동적으로 작성된 테이블 데이터를 리턴하기위한 스토어드 프로 시저


10

간단히 이야기하자면, 우리는 측량 시스템이있는 외부 공급 업체와 협력하고 있습니다. 새로운 측량을 만들 때 시스템이 새로운 테이블을 만들 때 시스템이 반드시 최상으로 설계된 것은 아닙니다.

Tables
____
Library_1 -- table for Survey 1
SurveyId int
InstanceId int
Q_1 varchar(50)

Library_2 -- table for Survey 2
SurveyId int
InstanceId int
Q_2 int
Q_3 int
Q_4 varchar(255)

표는 SurveyId이름 끝 ( Library_)으로 생성되고 질문 열은 QuestionId끝 ( Q_)으로 생성됩니다. 명확히하기 위해 질문은 별도의 테이블에 저장되므로 질문 ID는 순차적이지만 각 설문 조사마다 1에서 시작하지 않습니다. 질문 열은 표에서 할당 된 ID를 기준으로합니다.

다른 시스템으로 전송하기 위해 모든 측량 테이블에서 데이터를 추출해야하는 경우를 제외하고는 쿼리하기에 충분히 단순 해 보입니다. 여기에는 문제가 발생하는 곳이 있습니다. 다른 시스템은이 유형의 구조를 처리 할 수 ​​없습니다. 데이터를 일관성있게 사용해야합니다.

그래서 모든 Survey 테이블에서 데이터를 추출하여 다음 형식으로 저장하는 저장 프로 시저를 작성해야했습니다.

SurveyId    InstanceId    QNumber    Response
________    __________    _______    ________
1           1             1          great
1           2             1          the best
2           9             2          10
3           50            50         test

모든 테이블의 데이터를 동일한 형식으로 사용하면 설문 테이블 및 질문 수에 관계없이 누구나 사용할 수 있습니다.

나는 작동하는 것처럼 보이는 저장 프로 시저를 작성했지만 뭔가 빠졌는지 또는 이러한 유형의 상황을 처리하는 더 좋은 방법이 있는지 궁금합니다.

내 코드 :

declare @sql varchar(max) = ''
declare @RowCount int = 1
declare @TotalRecords int = (SELECT COUNT(*) FROM SurveyData)

Declare @TableName varchar(50) = ''
Declare @ColumnName varchar(50) = ''

WHILE @RowCount <= @TotalRecords
    BEGIN

        SELECT @TableName = tableName, @ColumnName = columnName
        FROM SurveyData
        WHERE @RowCount = rownum


        SET @sql = @sql + 
            ' SELECT s.SurveyId
                , s.InstanceId
                , CASE WHEN columnName = ''' +  @ColumnName + ''' THEN REPLACE(columnName, ''Q_'', '''') ELSE '''' END as QuestionNumber
                , Cast(s.' + @ColumnName + ' as varchar(1000)) as ''Response''
            FROM SurveyData t 
            INNER JOIN ' + @TableName + ' s' +
                ' ON REPLACE(t.tableName, ''Library_'', '''') = s.SurveyID ' +
            ' WHERE t.columnName = ''' + @ColumnName + ''''

        IF @RowCount != @TotalRecords
            BEGIN
                set @sql = @sql + ' UNION ALL'
            END

        SET @RowCount = @RowCount + 1       
    END


exec(@sql)

샘플 데이터와 코드 로 SQL Fiddle 을 만들었습니다 .

이 유형의 쿼리를 작성해야하는 다른 방법이 있습니까? 눈에 띄는 문제가 있습니까?

불행히도, 이것에 대한 많은 미지가 있습니다 ... 우리가 가질 테이블 수와 설문 당 몇 개의 질문이 있습니까? 25-50 건의 설문 조사가 있고 2 ~ 5 개의 질문이있을 것입니다.


1
묻기를 두려워하지만 "얼마나 많은 테이블이 있습니까?"
RBarryYoung

@RBarryYoung이 시점에서는 생성 된 측량의 수에 따라 달라지기 때문에 알 수 없습니다. 그것은 문제의 일부입니다.
Taryn

그럼 우리에게 범위를 줘. 매우 중요합니다.
RBarryYoung 1

나는 25-50 테이블 어디에서나 말할 것입니다.
Taryn

답변:


2

채팅에 참여한 사람들의 의견을 바탕으로 INSERT INTO마지막에 실행할 하나의 긴 SQL 문을 만드는 대신 스크립트를 임시 테이블로 약간 변경하기로 결정했습니다 . 결국 내 저장 프로 시저에는 다음이 포함됩니다.

create table #SurveyData
(
    tableName varchar(50),
    columnName varchar(50),
    columnId int,
    rownum int
)

create table #results
(
    SurveyId int,
    InstanceId int,
    QuestionNumber int,
    Response varchar(1000)
)

-- insert the survey table structures for use
insert into #SurveyData (tableName, columnName, columnId, rownum)
select tables1.name, cols1.name, column_id, ROW_NUMBER() over(order by tables1.name, column_id)
from sys.all_columns cols1
inner join 
(
    SELECT *
    FROM sys.all_objects
    WHERE type = 'U' 
    AND upper(name) like 'LIBRARY%' 
) Tables1
    ON cols1.object_id = tables1.object_id
WHERE cols1.name Like 'Q_%'
ORDER BY tables1.name, column_id;


declare @sql varchar(max) = '';
declare @RowCount int = 1;
declare @TotalRecords int = (SELECT COUNT(*) FROM #SurveyData);

Declare @TableName varchar(50) = '';
Declare @ColumnName varchar(50) = '';

WHILE @RowCount <= @TotalRecords
    BEGIN

        SELECT @TableName = tableName, @ColumnName = columnName
        FROM #SurveyData
        WHERE @RowCount = rownum

        SET @sql = 'INSERT INTO #results ' +
                    ' SELECT s.SurveyId
                        , s.InstanceId
                        , CASE WHEN columnName = ''' +  @ColumnName + ''' THEN REPLACE(columnName, ''Q_'', '''') ELSE '''' END as QuestionNumber
                        , Cast(s.' + @ColumnName + ' as varchar(1000)) as ''Response''
                    FROM #SurveyData t 
                    INNER JOIN ' + @TableName + ' s' +
                    ' ON REPLACE(t.tableName, ''Library_'', '''') = s.SurveyID ' +
                    ' WHERE t.columnName = ''' + @ColumnName + ''''

        exec(@sql)

        SET @RowCount = @RowCount + 1       
    END

    SELECT SurveyId, InstanceId, QuestionNumber, Response
    FROM #results

drop table #SurveyData
drop table #results

최종 스크립트와 함께 SQL Fiddle 을 참조하십시오

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.