Em breve, estamos trabalhando com um fornecedor externo que possui um sistema de pesquisa. O sistema não é necessariamente projetado da melhor maneira possível, quando você cria uma nova pesquisa e o sistema cria uma nova tabela, ou seja:
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)
As tabelas são geradas com o SurveyId
no final do nome ( Library_
) e as colunas de pergunta são geradas com o QuestionId
no final do ( Q_
). Para esclarecer, as perguntas são armazenadas em uma tabela separada, portanto, enquanto os IDs das perguntas são seqüenciais, eles não começam em 1 para cada pesquisa. As colunas da pergunta serão baseadas no ID atribuído a elas na tabela.
Parece simples o suficiente para consultar, exceto que precisamos extrair os dados de todas as tabelas de pesquisa a serem enviadas para outro sistema e é aí que entra o problema. Como as tabelas são criadas automaticamente quando uma nova pesquisa é adicionada pelo front- aplicação final, o outro sistema não pode lidar com esse tipo de estrutura. Eles precisam que os dados sejam consistentes para serem consumidos.
Por isso, fui encarregado de escrever um procedimento armazenado que extraia os dados de todas as tabelas de pesquisa e os coloque no seguinte formato:
SurveyId InstanceId QNumber Response
________ __________ _______ ________
1 1 1 great
1 2 1 the best
2 9 2 10
3 50 50 test
Ao ter os dados de todas as tabelas no mesmo formato, eles podem ser consumidos por qualquer pessoa, independentemente de quantas tabelas e perguntas de pesquisa existam.
Eu escrevi um procedimento armazenado que parece estar funcionando, mas estou me perguntando se estou faltando alguma coisa ou se existe uma maneira melhor de lidar com esse tipo de situação.
Meu código:
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)
Eu criei um SQL Fiddle com alguns dados de amostra e o código.
Existe uma maneira diferente de escrever esse tipo de consulta? Existem problemas visíveis com ele?
Infelizmente, existem muitas incógnitas com isso ... quantas tabelas teremos e quantas perguntas por pesquisa. Eu diria que teremos entre 25 e 50 pesquisas, com 2 a 5 perguntas cada.
Respostas:
Com base nos comentários de pessoas no bate-papo, decidi alterar meu script levemente para
INSERT INTO
uma tabela temporária em vez de criar uma instrução SQL longa para executar no final. Portanto, no final, meu procedimento armazenado contém o seguinte:Veja SQL Fiddle com o script final
fonte