Quelle requête ou vue SQL affichera «colonnes dynamiques»
Question
J'ai une table de données et j'autorise les gens à ajouter des métadonnées à cette table.
Je leur donne une interface qui leur permet de le traiter comme s'ils ajoutaient des colonnes supplémentaires à la table dans laquelle leurs données sont stockées, mais je stocke en fait les données dans une autre table.
Data Table
DataID
Data
Meta Table
DataID
MetaName
MetaData
Donc, s'ils voulaient une table qui stocke les données, la date et un nom, les données figureraient dans la table de données et le mot "Date". dans le métaname et la date dans MetaData, ainsi qu'une autre ligne de la table meta avec l'option "Nom". dans le métaname et le nom dans les métadonnées.
J'ai maintenant besoin d'une requête qui extrait les informations de ces tables et les présente comme si elles provenaient d'une seule table avec les deux colonnes supplémentaires " Données " et " Nom " pour le client, il semblerait qu'il y ait une seule table avec leurs colonnes personnalisées:
MyTable
Data
Date
Name
Ou, en d'autres termes, comment puis-je partir d'ici:
Data Table
DataID Data
1 Testing!
2 Hello, World!
Meta Table
DataID MetaName MetaData
1 Date 20081020
1 Name adavis
2 Date 20081019
2 Name mdavis
Jusqu'ici:
MyTable
Data Date Name
Testing! 20081020 adavis
Hello, World! 20081019 mdavis
Il y a des années, lorsque je travaillais dans PHP avec MySQL, j'ai effectué deux requêtes, la première pour obtenir les métadonnées supplémentaires et la seconde pour les réunir. J'espère que les bases de données modernes disposent de méthodes alternatives pour gérer ce problème.
Lié à l'option 3 de la question .
-Adam
La solution
Vous souhaitez faire pivoter chacune des lignes de votre paire nom-valeur dans la table MyTable ... Essayez ceci SQL:
DECLARE @Data TABLE (
DataID INT IDENTITY(1,1) PRIMARY KEY,
Data VARCHAR(MAX)
)
DECLARE @Meta TABLE (
DataID INT ,
MetaName VARCHAR(MAX),
MetaData VARCHAR(MAX)
)
INSERT INTO @Data
SELECT 'Data'
INSERT INTO @Meta
SELECT 1, 'Date', CAST(GetDate() as VARCHAR(20))
UNION
SELECT 1, 'Name', 'Joe Test'
SELECT * FROM @Data
SELECT * FROM @Meta
SELECT
D.DataID,
D.Data,
MAX(CASE MetaName WHEN 'Date' THEN MetaData ELSE NULL END) as Date,
MAX(CASE MetaName WHEN 'Name' THEN MetaData ELSE NULL END) as Name
FROM
@Meta M
JOIN @Data D ON M.DataID = D.DataID
GROUP BY
D.DataID,
D.Data
Autres conseils
SELECT DataTable.Data AS Data, MetaTable.MetaData AS Date, MetaTable.MetaName AS Name
FROM DataTable, MetaTable
WHERE DataTable.DataID = MetaTable.DataID
Vous voudrez probablement ajouter une clause supplémentaire (AND Data = 'une valeur') pour renvoyer les lignes qui intéressent l'utilisateur.
SQL
.
Le code que vous souhaitez générer de manière dynamique est le suivant:
SELECT [Data Table].*
,[MyTable Date].MetaData
,[MyTable Name].MetaData
FROM [Data Table]
LEFT JOIN [MyTable] AS [MyTable Date]
ON [MyTable Date].DataID = [Data Table].DataID
AND [MyTable Date].MetaName = 'Date'
LEFT JOIN [MyTable] AS [MyTable Name]
ON [MyTable Name].DataID = [Data Table].DataID
AND [MyTable Name].MetaName = 'Name'
Et voici le code pour le faire:
DECLARE @sql AS varchar(max)
DECLARE @select_list AS varchar(max)
DECLARE @join_list AS varchar(max)
DECLARE @CRLF AS varchar(2)
DECLARE @Tab AS varchar(1)
SET @CRLF = CHAR(13) + CHAR(10)
SET @Tab = CHAR(9)
SELECT @select_list = COALESCE(@select_list, '')
+ @Tab + ',[MyTable_' + PIVOT_CODE + '].[MetaData]' + @CRLF
,@join_list = COALESCE(@join_list, '')
+ 'LEFT JOIN [MyTable] AS [MyTable_' + PIVOT_CODE + ']' + @CRLF
+ @Tab + 'ON [MyTable_' + PIVOT_CODE + '].DataID = [DataTable].DataID' + @CRLF
+ @Tab + 'AND [MyTable_' + PIVOT_CODE + '].MetaName = ''' + PIVOT_CODE + '''' + @CRLF
FROM (
SELECT DISTINCT MetaName AS PIVOT_CODE
FROM [MyTable]
) AS PIVOT_CODES
SET @sql = 'SELECT [DataTable].*' + @CRLF
+ @select_list
+ 'FROM [DataTable]' + @CRLF
+ @join_list
PRINT @sql
--EXEC (@sql)
Vous pouvez utiliser une technique dynamique similaire en utilisant l'exemple d'instruction CASE
pour effectuer le pivot.