2009-10-06 9 views
2

Utilisation de SQL, comment puis-je convertir une seule table de ligne comme celui-ci ...Comment créer une table de paires nom-valeur dans SQL

Firstname Surname Address1  City Country 
--------- ------- --------------- ------ ------- 
Bob  Smith 101 High Street London UK 

... à une table de nom valeur paires comme ceci:

Name  Value 
--------- ------- 
Firstname Bob 
Surname  Smith 
Address1 101 High Street 
City  London 
Country  UK 

ce script crée la table d'origine:

create table #OriginalTable (Firstname varchar(10), Surname varchar(10), 
Address1 varchar(50), City varchar(10), Country varchar(10)) 
insert into #OriginalTable 
select 
'Bob' Firstname, 
'Smith' Surname, 
'101 High Street' Address1, 
'London' City, 
'UK' Country 

Je suis après une génération solution eric qui ne dépend pas des noms des colonnes étant toujours ce qu'ils sont dans l'exemple.

EDIT: J'utilise SQL Server 2005. La solution que je suis après le script SQL pour convertir ces données dans une table de paires nom-valeur

RÉPONSE: En utilisant la réponse que j'ai accepté comme la réponse, ce que je l'ai utilisé:

select 
result.Name, 
result.Value  
from 
    (select 
    convert(sql_variant,FirstName) AS FirstName, 
    convert(sql_variant,Surname) AS Surname, 
    convert(sql_variant,Address1) AS Address1, 
    convert(sql_variant,City) AS City, 
    convert(sql_variant,Country) AS Country 
    from #OriginalTable) OriginalTable 
    UNPIVOT (Value For Name In (Firstname, Surname, Address1, City, Country)) as result 
+1

Quel SGBD utilisez-vous? Les différents SGBD stockent différemment les noms des colonnes. –

+0

Donc, vous auriez plusieurs lignes pour chaque clé? par exemple. Si la table d'origine n'avait pas seulement une ligne pour Bob Smith, mais aussi pour John Doe, votre table de paires nom-valeur aurait 2 lignes pour chaque clé. –

+0

@Dominic. Non, la table d'origine n'aura toujours qu'une seule ligne. S'il y a plus de lignes dans la base de données pour différentes personnes, la table d'origine n'aurait qu'une seule ligne, b/c c'est juste un filtre pour une seule personne. –

Répondre

6

Fondamentalement, vous avez deux problèmes - à UNPIVOT, les types de données doivent être conformes. L'autre problème est que le nombre de colonnes est inconnu. Vous voulez atteindre quelque chose de la forme:

WITH conformed 
     AS (SELECT CONVERT(VARCHAR(255), [Firstname]) AS [Firstname], 
        CONVERT(VARCHAR(255), [Surname]) AS [Surname], 
        CONVERT(VARCHAR(255), [Address1]) AS [Address1], 
        CONVERT(VARCHAR(255), [City]) AS [City], 
        CONVERT(VARCHAR(255), [Country]) AS [Country] 
      FROM  so1526080 
     ) 
SELECT ColumnKey, 
     ColumnValue 
FROM conformed UNPIVOT (ColumnValue FOR ColumnKey IN ([Firstname], [Surname], [Address1], [City], [Country])) AS unpvt 

Donc, en utilisant une PIVOT SQL dynamique à l'aide de métadonnées (vous pourriez avoir besoin de résoudre ce problème avec TABLE_SCHEMA, etc.):

DECLARE @table_name AS SYSNAME 
SET @table_name = 'so1526080' 
DECLARE @conform_data_type AS VARCHAR(25) 
SET @conform_data_type = 'VARCHAR(255)' 

DECLARE @column_list AS VARCHAR(MAX) 
DECLARE @conform_list AS VARCHAR(MAX) 

SELECT @conform_list = COALESCE(@conform_list + ', ', '') + 'CONVERT(' 
     + @conform_data_type + ', ' + QUOTENAME(COLUMN_NAME) + ') AS ' 
     + QUOTENAME(COLUMN_NAME), 
     @column_list = COALESCE(@column_list + ', ', '') 
     + QUOTENAME(COLUMN_NAME) 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = @table_name 

DECLARE @template AS VARCHAR(MAX) 

SET @template = ' 
WITH conformed 
      AS (SELECT {@conform_list} 
       FROM  {@table_name} 
      ) 
    SELECT ColumnKey, 
      ColumnValue 
    FROM conformed UNPIVOT (ColumnValue FOR ColumnKey IN ({@column_list})) AS unpvt 
    ' 

DECLARE @sql AS VARCHAR(MAX) 
SET @sql = REPLACE(REPLACE(REPLACE(@template, '{@conform_list}', @conform_list), 
          '{@column_list}', @column_list), '{@table_name}', 
        @table_name)  

PRINT @sql 
EXEC (@sql 
    ) 
+1

+1 - Très bien! –

-1

cela sonne comme le genre de choses la clause PIVOT peut faire SQL Server depuis 2005 (chercher le premier exemple), mais vous ne mentionnez pas qui moteur de base de données que vous utilisez.

+0

Je ne pense pas que vous pouvez PIVOT sans savoir ce que les noms de champs sont. Mais si vous le pouvez, s'il vous plaît poster le SQL –

+0

Désolé, je n'utilise pas SQL Server moi-même, seulement lire dans les docs de Microsoft. –

0

Non que ce soit une solution complète, mais une idée de remue-méninges, que se passe-t-il si vous vous joignez à information_schema.columns avec votre table?

SELECT column_name, OriginalTable.* 
FROM information_schema.columns 
CROSS JOIN OriginalTable 
WHERE table_name = 'OriginalTable' 
AND /* PRIMARY KEY FILTER HERE*/ 
0

Souvent, il est plus efficace de pivoter dans l'application en utilisant le code d'application. Le pivot ne tend pas à être le point fort d'une base de données.

0

Utilisez deux tables. Une table en tant que table de «clés» et la table principale contient un ID à la table de clés, avec une valeur.

Ensuite, vous pouvez également ajouter des éléments comme client_id ou autre dans la table principale et définir une clé unique sur client_id et key_id.

Questions connexes