将连接表的列旋转为行

Rotate columns to rows for joined tables

我有两个类似于下图的 table(为简单起见,省略了字段)。

Table lead :

 id  |  fname    |   lname    |     email
 ---------------------------------------------
 1   |  John     |   Doe      |    jd@test.com
 2   |  Mike     |   Johnson  |    mj@test.com

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

我有一个数据库可以捕获各种表单的潜在客户,这些表单通常有许多不同的表单字段。第一个 table 获取我所知道的每个表格上的基本信息。第二个 table 捕获发送过来的所有其他表单字段,因此它实际上可以包含很多不同的字段。

我想做的是做一个连接,我可以从 lead table 中获取所有字段以及 utm_mediumutm_term 来自 [=14] =] table。我不需要任何额外的字段,即使它们已发送过来。

想要的结果:

 id    |  fname    |    lname   |   email       |  utm_medium   |  utm_term
 ---------------------------------------------------------------------------
 1     |  John     |    Doe     |   jd@test.com |  cpc          |  fall
 2     |  Mike     |    Johnson |   mj@test.com |  display      |  summer

我知道我可以做到这一点的唯一方法是获取所有潜在客户数据,然后针对每条记录进行更多调用以获取我正在寻找的 leadcustom 数据,但我知道我必须有一种更有效的方法获取此数据。

我很感激任何帮助,这不是我可以改变我捕获数据的方式和 table 格式的东西。

如果你的列是固定的,你可以像这样用 group by + case + max 来做到这一点:

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

案例会在与给定名称匹配时从 leadcustom table 赋值,否则它将 return 为 null,如果它存在于 null 之上,max 将选择分配的值。

您可以在 SQL Fiddle

中进行测试

另一种方法是使用数据透视运算符,但该语法稍微复杂一些——或者至少这对我来说更容易。

你可以试试 pivotjoin:

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 通过将表达式中 [value] 列的 unique 值转换为 [utm_medium][utm_term] 列在输出中,并使用 max 函数执行假聚合( 它之所以有效,是因为相应的列对于一个唯一的旋转列可以有多个值,在此案例,[name] for [value]).

SQLFiddle

您可以使用 cte 或派生的 table 来解决这个问题:

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:

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)

并且由于 suslov 使用了 JamesZ 的 fiddle,I will use it too...

除非我错误地解释了你的问题——在这种情况下,我很乐意得到纠正——你可以通过一个简单的左连接来实现你的目标,你可以在第一个 table:[=11 的 ID 上连接=]

select ld.*, ldcust.utm_medium, ldcust.utm_term 
from lead ld
left join leadcustom ldcust 
on ld.id = ldcust.leadid
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','jd@test.com'),(2,'mike','johnson','mj@test.com')
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 @t t JOIN @tt tt
   ON t.Id = tt.leadid)R
PIVOT(MAX(value) for name IN([utm_medium],[utm_term]))P