2011-08-04 2 views
0

En utilisant SQL Server 2005 je les tableaux suivants:Valeurs de retour SQL en tant que champs basés sur la table de type clé et valeur - PIVOT, CASE, etc?

Valeur:

ValueID UserID ValueTypeID ValueKey Text Number 
------------------------------------------------------ 
1  345  1   NAME  Bob NULL 
2  345  2   AGE  NULL 30 
3  689  1   NAME  Sam NULL 
4  689  2   AGE  NULL 45 

ValueType:

ValueTypeID CodeName 
--------------------- 
1   TEXT 
2   NUMBER 

Je souhaite obtenir des résultats comme:

UserID Name Age 
----------------- 
345  Bob 30 
689  Sam 45 

I Je suis sûr que c'est possible, en utilisant un pivot et peut-être quelques déclarations de cas? Il y a plus de ValueKeys, et encore plus de ValueTypes mais ça va me permettre de continuer. Je connais la liste des ValueKeys à l'avance, ce qui signifie que je peux éviter une requête dynamique.

Répondre

0

La résolution devrait être de re-concevoir la table. La recherche valueType est complètement inutile telle que mise en œuvre. Vous devriez juste avoir une seule colonne "ValueText" au lieu de "Text", "Number", ... et stocker toutes les valeurs dans cette colonne. Ensuite, ce serait une simple déclaration join.

+0

Malheureusement, je suis Interrogation d'une base de données existante. Je suis incapable à ce stade de changer son design. Aussi le texte est un champ nvarchar, le nombre est un champ int, il y a aussi un champ date de type datetime, etc. – Sprintstar

0

Vous pouvez regrouper par ID utilisateur et utiliser une sous-requête pour obtenir les valeurs de champ.

declare @T table 
(
    ValueID int, 
    UserID int, 
    ValueTypeID int, 
    ValueKey varchar(10), 
    Text varchar(10), 
    Number int 
) 

insert into @T values 
(1,  345,  1,   'NAME',  'Bob', NULL), 
(2,  345,  2,   'AGE',  NULL, 30), 
(3,  689,  1,   'NAME',  'Sam', NULL), 
(4,  689,  2,   'AGE',  NULL, 45) 

select T1.UserID, 
     (select [Text] 
     from @T as T2 
     where T1.UserID = T2.UserID and 
       T2.ValueKey = 'NAME') as Name, 
     (select Number 
     from @T as T2 
     where T1.UserID = T2.UserID and 
       T2.ValueKey = 'AGE') as Age 
from @T as T1 
group by T1.UserID 
1

Une requête pivot classique. Ensuite, vous pouvez utiliser le ValueTypeID si vous voulez:

SELECT UserID, 
     MAX(
      CASE WHEN ValueKey = 'NAME' 
       THEN 
        CASE WHEN ValueTypeID = 1 
          THEN Text 
         WHEN ValueTypeID = 2 
          THEN Number 
         WHEN ValueTypeID = 3 
          THEN Date 
         ELSE NULL 
        END 
       ELSE NULL 
      END 
     ) AS Name, 
     MAX(
      CASE WHEN ValueKey = 'AGE' 
       THEN 
        CASE WHEN ValueTypeID = 1 
          THEN Text 
         WHEN ValueTypeID = 2 
          THEN Number 
         WHEN ValueTypeID = 3 
          THEN Date 
         ELSE NULL 
        END 
       ELSE NULL 
      END 
     ) AS Age, 
     MAX(
      CASE WHEN ValueKey = 'DATEBIRTH' 
       THEN 
        CASE WHEN ValueTypeID = 1 
          THEN Text 
         WHEN ValueTypeID = 2 
          THEN Number 
         WHEN ValueTypeID = 3 
          THEN Date 
         ELSE NULL 
        END 
       ELSE NULL 
      END 
     ) AS DateBirth 
FROM Value 
GROUP BY UserID 

Mais il est peut-être inutile, vous pouvez juste être moins générique avec moins de code:

SELECT UserID, 
     MAX(
      CASE WHEN ValueKey = 'NAME' 
       THEN Text -- I know that name is a string 
       ELSE NULL 
      END 
     ) AS Name, 
     MAX(
      CASE WHEN ValueKey = 'AGE' 
       THEN Number -- I know that age is a number 
       ELSE NULL 
      END 
     ) AS Age, 
     MAX(
      CASE WHEN ValueKey = 'DATEBIRTH' 
       THEN Date -- I know that date of birth is a date 
       ELSE NULL 
      END 
     ) AS DateBirth 
FROM Value 
GROUP BY UserID 
+0

Comment est-ce que j'allongerais ceci pour traiter une clé de date de naissance et un autre type de valeur DATE? – Sprintstar

+0

+1, vous pouvez également omettre 'ELSE NULL', car il est implicite si' ELSE' n'est pas spécifié. –

Questions connexes