Breve historia de fondo, estamos trabajando con un proveedor externo que tiene un sistema de encuestas. El sistema no está necesariamente diseñado mejor cuando crea una nueva encuesta y crea una nueva tabla, es decir:
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)
Las tablas se generan con el SurveyId
al final del nombre ( Library_
) y las columnas de Preguntas se generan con el QuestionId
al final ( Q_
). Para aclarar, las preguntas se almacenan en una tabla separada, por lo que si bien los identificadores de preguntas son secuenciales, no comienzan en 1 para cada encuesta. Las columnas de preguntas se basarán en la identificación asignada en la tabla.
Parece bastante simple para consultar, excepto que necesitamos extraer los datos de todas las tablas de encuestas para enviarlas a otro sistema y aquí es donde entra el problema. Dado que las tablas se crean automáticamente cuando el frente agrega una nueva encuesta Al finalizar la aplicación, el otro sistema no puede manejar este tipo de estructura. Necesitan que los datos sean consistentes para que puedan consumir.
Así que me encargaron escribir un procedimiento almacenado que extraiga los datos de todas las tablas de la Encuesta y lo coloque en el siguiente formato:
SurveyId InstanceId QNumber Response
________ __________ _______ ________
1 1 1 great
1 2 1 the best
2 9 2 10
3 50 50 test
Al tener los datos de todas las tablas en el mismo formato, cualquiera puede consumirlos sin importar cuántas tablas de encuesta y preguntas existan.
Escribí un procedimiento almacenado que parece estar funcionando, pero me pregunto si me falta algo o si hay una mejor manera de manejar este tipo de situación.
Mi 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)
He creado un SQL Fiddle con algunos datos de muestra y el código.
¿Hay alguna forma diferente de escribir este tipo de consulta? ¿Hay algún problema notable con él?
Desafortunadamente, hay muchas incógnitas con esto ... cuántas tablas tendremos y cuántas preguntas por encuesta. Yo diría que tendremos entre 25 y 50 encuestas, con 2-5 preguntas cada una.