我有一个设计糟糕的表,它有行和列的混合,它可能应该有1行,有很多列或完全是其他设计。但这个错误是在20年前,在别人的监视下。
现在我正在通过无数的自我加入来完成我想要的观点。这很痛苦。
以下将介绍我现在的工作方式:
declare @client table
(
clientNumber int,
name varchar(10)
)
insert into @client values (1, 'Bob');
insert into @client values (2, 'Alice');
declare @options table
(
clientNumber int,
optionKey varchar(4),
optionValue1 int,
optionValue2 int,
optionValue3 int
)
insert into @options values (1, 'optA', 1, 1, 0);
insert into @options values (1, 'optB', 0, 1, 0);
insert into @options values (2, 'optA', 1, 1, 1);
insert into @options values (2, 'optC', 0, 0, 1);
select c.clientNumber, c.name,
oA.optionValue1 as [Graduated],
oA.optionValue2 as [Employed],
oA.optionValue3 as [Married],
oB.optionValue1 as [HasPets],
oB.optionValue2 as [LikesThai],
oB.optionValue3 as [MathWiz],
oC.optionValue1 as [DrvLicense],
oC.optionValue2 as [Registered],
oC.optionValue3 as [Outdoorsy]
from @client c
left outer join @options oA
on oA.clientNumber = c.clientNumber and oA.optionKey = 'optA'
left outer join @options oB
on oB.clientNumber = c.clientNumber and oB.optionKey = 'optB'
left outer join @options oC
on oC.clientNumber = c.clientNumber and oC.optionKey = 'optC'
对于这些结果:
结果集正是我想要的。并非每个客户端都有A,B或C记录,因此结果集中的null
正常。经过一段时间的搜索,我找不到这样的例子,所以我不确定PIVOT
是不是我正在寻找的。建议?
更新: 这似乎产生了相同的结果。我将在更大的案例上测试它,看看它是否比所有自连接更快。 (我怀疑是)。我还是想知道我是不是用支点吠叫了错误的树。
select clientNumber,
Min(Case o.optionKey when 'optA' then o.optionValue1 end) [Graduated],
Min(Case o.optionKey when 'optA' then o.optionValue2 end) [Employed],
Min(Case o.optionKey when 'optA' then o.optionValue3 end) [Married],
Min(Case o.optionKey when 'optB' then o.optionValue1 end) [HasPets],
Min(Case o.optionKey when 'optB' then o.optionValue2 end) [LikesThai],
Min(Case o.optionKey when 'optB' then o.optionValue3 end) [MathWix],
Min(Case o.optionKey when 'optC' then o.optionValue1 end) [DrvLicense],
Min(Case o.optionKey when 'optC' then o.optionValue2 end) [Registered],
Min(Case o.optionKey when 'optC' then o.optionValue3 end) [Outdoorsy]
from @options o
group by clientnumber
答案 0 :(得分:2)
以下是几个选项。两种解决方案都使用一种技术来支撑数据。第一个解决方案会将您的NULL更改为0。
SELECT c.clientNumber, c.name,
MAX(CASE WHEN o.optionKey = 'optA' THEN o.optionValue1 ELSE 0 END) AS [Graduated],
MAX(CASE WHEN o.optionKey = 'optA' THEN o.optionValue2 ELSE 0 END) AS [Employed],
MAX(CASE WHEN o.optionKey = 'optA' THEN o.optionValue3 ELSE 0 END) AS [Married],
MAX(CASE WHEN o.optionKey = 'optB' THEN o.optionValue1 ELSE 0 END) AS [HasPets],
MAX(CASE WHEN o.optionKey = 'optB' THEN o.optionValue2 ELSE 0 END) AS [LikesThai],
MAX(CASE WHEN o.optionKey = 'optB' THEN o.optionValue3 ELSE 0 END) AS [MathWiz],
MAX(CASE WHEN o.optionKey = 'optC' THEN o.optionValue1 ELSE 0 END) AS [DrvLicense],
MAX(CASE WHEN o.optionKey = 'optC' THEN o.optionValue2 ELSE 0 END) AS [Registered],
MAX(CASE WHEN o.optionKey = 'optC' THEN o.optionValue3 ELSE 0 END) AS [Outdoorsy]
FROM @client c
LEFT OUTER JOIN @options o
ON o.clientNumber = c.clientNumber
GROUP BY c.clientNumber, c.name
ORDER BY c.clientNumber, c.name
第二个解决方案保留NULL值。但是,它需要从BIT到TINYINT的显式类型转换,因为MAX函数在BIT数据类型上失败。
SELECT c.clientNumber, c.name,
MAX(CASE WHEN o.optionKey = 'optA' THEN CAST (o.optionValue1 AS TINYINT) END) AS [Graduated],
MAX(CASE WHEN o.optionKey = 'optA' THEN CAST (o.optionValue2 AS TINYINT) END) AS [Employed],
MAX(CASE WHEN o.optionKey = 'optA' THEN CAST (o.optionValue3 AS TINYINT) END) AS [Married],
MAX(CASE WHEN o.optionKey = 'optB' THEN CAST (o.optionValue1 AS TINYINT) END) AS [HasPets],
MAX(CASE WHEN o.optionKey = 'optB' THEN CAST (o.optionValue2 AS TINYINT) END) AS [LikesThai],
MAX(CASE WHEN o.optionKey = 'optB' THEN CAST (o.optionValue3 AS TINYINT) END) AS [MathWiz],
MAX(CASE WHEN o.optionKey = 'optC' THEN CAST (o.optionValue1 AS TINYINT) END) AS [DrvLicense],
MAX(CASE WHEN o.optionKey = 'optC' THEN CAST (o.optionValue2 AS TINYINT) END) AS [Registered],
MAX(CASE WHEN o.optionKey = 'optC' THEN CAST (o.optionValue3 AS TINYINT) END) AS [Outdoorsy]
FROM @client c
LEFT OUTER JOIN @options o
ON o.clientNumber = c.clientNumber
GROUP BY c.clientNumber, c.name
ORDER BY c.clientNumber, c.name
答案 1 :(得分:0)
我不确定它的表现,但我会这样做:
select c.clientNumber, c.name,
oA.optionValue1 as [Graduated],
oA.optionValue2 as [Employed],
oA.optionValue3 as [Married],
oB.optionValue1 as [HasPets],
oB.optionValue2 as [LikesThai],
oB.optionValue3 as [MathWiz],
oC.optionValue1 as [DrvLicense],
oC.optionValue2 as [Registered],
oC.optionValue3 as [Outdoorsy]
from @client c
OUTER APPLY (SELECT * FROM @options WHERE optionkey = 'optA' And clientnumber = c.clientnumber) oA
OUTER APPLY (SELECT * FROM @options WHERE optionkey = 'optB' And clientnumber = c.clientnumber) oB
OUTER APPLY (SELECT * FROM @options WHERE optionkey = 'optC' And clientnumber = c.clientnumber) oC
或CTE可能有用
with t as
(select oA.ClientNumber,
oA.optionValue1 as [Graduated],
oA.optionValue2 as [Employed],
oA.optionValue3 as [Married],
oB.optionValue1 as [HasPets],
oB.optionValue2 as [LikesThai],
oB.optionValue3 as [MathWiz],
oC.optionValue1 as [DrvLicense],
oC.optionValue2 as [Registered],
oC.optionValue3 as [Outdoorsy]
from
(SELECT * FROM @options WHERE optionkey = 'optA') oA
OUTER APPLY (SELECT * FROM @options WHERE optionkey = 'optB' And clientnumber = oA.clientnumber) oB
OUTER APPLY (SELECT * FROM @options WHERE optionkey = 'optC' And clientnumber = oA.clientnumber) oC )
select c.clientNumber, c.name,
t.[Graduated],
t.[Employed],
t.[Married],
t.[HasPets],
t.[LikesThai],
t.[MathWiz],
t.[DrvLicense],
t.[Registered],
t.[Outdoorsy]
from @client c join t on c.clientnumber = t.clientnumber