กระบวนงานที่เก็บไว้เพื่อส่งคืนข้อมูลตารางที่สร้างขึ้นแบบไดนามิก


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_) ในการชี้แจงคำถามจะถูกเก็บไว้ในตารางแยกต่างหากดังนั้นในขณะที่รหัสคำถามนั้นเรียงตามลำดับโดยไม่เริ่มต้นที่ 1 สำหรับแต่ละแบบสำรวจ คอลัมน์คำถามจะขึ้นอยู่กับรหัสที่กำหนดให้กับพวกเขาในตาราง

ดูเหมือนง่ายพอที่จะสืบค้นยกเว้นเราจำเป็นต้องดึงข้อมูลจากตารางสำรวจทั้งหมดที่จะส่งไปยังระบบอื่นและนี่คือที่มาของปัญหาเนื่องจากตารางจะถูกสร้างขึ้นโดยอัตโนมัติเมื่อมีการเพิ่มแบบสำรวจใหม่โดยหน้า แอปพลิเคชันสิ้นสุดระบบอื่นไม่สามารถจัดการกับโครงสร้างประเภทนี้ได้ พวกเขาต้องการข้อมูลที่สอดคล้องกันเพื่อให้สามารถบริโภคได้

ดังนั้นฉันจึงมอบหมายให้เขียนโพรซีเดอร์ที่เก็บไว้ซึ่งจะดึงข้อมูลจากตารางสำรวจทั้งหมดและวางไว้ในรูปแบบต่อไปนี้:

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

ฉันจะพูดได้ทุกที่จาก 25-50 ตาราง
Taryn

คำตอบ:


2

จากความคิดเห็นของผู้คนในการแชทฉันตัดสินใจที่จะเปลี่ยนสคริปต์ของฉันเล็กน้อยไปยังINSERT INTOตาราง temp แทนที่จะสร้างคำสั่ง 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.