存储过程返回动态创建的表数据


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是连续的,但对于每个调查来说,问题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在这一点上是未知的,因为这取决于创建多少个调查。那是问题的一部分。
塔林

给我们一个范围。这很重要。
RBarryYoung

我会说从25-50桌的任何地方。
塔林

Answers:


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.