Rotation des colonnes en lignes pour les tables jointes

J'ai deux arrays similaires à ceux montrés ci-dessous (en laissant simplement de côté les champs pour plus de simplicité).

lead table:

  id | fname | lname | email --------------------------------------------- 1 | John | Doe | [email protected] 2 | Mike | Johnson | [email protected] 

Table leadcustom :

  id | leadid | name | value ------------------------------------------------- 1 | 1 | utm_medium | cpc 2 | 1 | utm_term | fall 3 | 1 | subject | business 4 | 2 | utm_medium | display 5 | 2 | utm_term | summer 6 | 2 | month | may 7 | 2 | color | red 

J'ai une database qui capture des pistes pour une grande variété de forms qui ont souvent de nombreux champs de formulaire différents. La première table obtient les informations de base que je connais sur chaque formulaire. La deuxième table capture tous les autres champs de formulaires qui ont été envoyés afin qu'elle puisse contenir beaucoup de champs différents.

Ce que j'essaye de faire est de faire une jointure où je peux saisir tous les champs de lead table lead avec utm_medium et utm_term de la table leadcustom . Je n'ai pas besoin de champs supplémentaires même s'ils ont été envoyés.

Les résultats souhaités :

  id | fname | lname | email | utm_medium | utm_term --------------------------------------------------------------------------- 1 | John | Doe | [email protected] | cpc | fall 2 | Mike | Johnson | [email protected] | display | summer 

La seule façon que je sais que je pourrais faire ceci est d'attraper toutes datatables principales et ensuite pour chaque logging faire plus d'appels pour get des données personnalisées que je cherche mais je sais qu'il y a un moyen plus efficace d'get ces données.

J'apprécie n'importe quelle aide avec ceci et ce n'est pas quelque chose que je peux changer la manière dont je capture ces données et formats de tableau.

Si vos colonnes sont fixes, vous pouvez le faire avec group by + case + max comme ceci:

 select fname, lname, email, max(case when name = 'utm_medium' then value end) as utm_medium, max(case when name = 'utm_term' then value end) as utm_term from lead l join leadcustom c on l.id = c.leadid group by fname, lname, email 

Le cas va assigner une valeur à partir de la table leadcustom quand elle correspond au nom donné, sinon elle returnnera null, et max choisira prendre la valeur assignée si elle existe sur la valeur null.

Vous pouvez tester cela dans SQL Fiddle

L'autre façon de faire est d'utiliser l'opérateur de pivot, mais cette syntaxe est légèrement plus complexe – ou du less c'est plus facile pour moi.

À less que j'interprète mal votre question – dans ce cas, je suis heureux d'être corrigé – vous pouvez atteindre votre objective avec une simple jointure à gauche où vous rejoignez sur l'ID de la première table:

 select ld.*, ldcust.utm_medium, ldcust.utm_term from lead ld left join leadcustom ldcust on ld.id = ldcust.leadid 

Vous pouvez utiliser un cte ou une table dérivée pour résoudre ceci:

cte:

 ;with cte as ( select leadid, [name], [value] from leadcustom where name in('utm_medium', 'display') ) select id, fname, lname, email, [name], [value] from lead inner join cte on(id = leadid) 

Table dérivée:

 select id, fname, lname, email, [name], [value] from lead inner join ( select leadid, [name], [value] from leadcustom where name in('utm_medium', 'display') ) derived on(id = leadid) 

et puisque suslov a utilisé le violon de JamesZ, je vais l'utiliser aussi …

 declare @t table (Id int,fname varchar(10),lname varchar(10),email varchar(20)) insert into @t(Id,fname,lname,email)values (1,'john','doe','[email protected]'),(2,'mike','johnson','[email protected]') declare @tt table (id int,leadid int,name varchar(10),value varchar(10)) insert into @tt(id,leadid,name,value)values (1,1,'utm_medium','cpc'), (2,1,'utm_term','fall'), (3,1,'subject','business'), (4,2,'utm_medium','display'), (5,2,'utm_term','summer'), (6,2,'month','may'),(7,2,'color','red') select Id,fname,lname, email, [utm_medium], [utm_term] from ( select t.Id, t.fname, t.lname, t.email, tt.name, tt.value from @tt JOIN @tt tt ON t.Id = tt.leadid)R PIVOT(MAX(value) for name IN([utm_medium],[utm_term]))P 

Vous pouvez essayer avec le pivot et join :

 select [id] , [fname] , [lname] , [email] , [utm_medium] , [utm_term] from ( select t2.* , t1.[name] , t1.[value] from [leadcustom] t1 join [lead] t2 on t2.[id] = t1.[leadid] ) t pivot ( max([value]) for [name] in ([utm_medium], [utm_term]) ) pt 

pivot fait pivoter l'expression table-jointe, en transformant les valeurs uniques de la colonne [value] de l'expression en [utm_medium] et [utm_term] dans la sortie, et effectue une fausse agrégation avec max fonction max ( cela fonctionne parce qu'une colonne correspondante peut avoir plusieurs valeurs pour une colonne pivotante unique, dans ce cas, [name] pour [value] ) .

SQLFiddle