我有以下两个表数据结构来处理自定义用户字段:
[UserFieldID] [UserFieldName] ------------------------------- 1 Location 2 Color [UserID] [UserFieldID] [UserFieldValue] ---------------------------------------- 1 1 Home 1 2 Orange 2 1 Office 2 2 Red
这允许定义(全局)任意数量的字段,并允许用户具有这些自定义字段的值。我需要弄清楚如何将这些信息显示为报告目的,作为预先存在的报告的一部分,采用以下格式:
UserID ... Location Color ---------------------------------------------------- 1 Home Orange 2 Office Red
我知道这可能涉及使用PIVOT或UNPIVOT,但尽可能尝试,他们只会让我感到困惑。
提前致谢
答案 0 :(得分:4)
有几种不同的方法可以获得结果,您可以使用带有CASE表达式的聚合函数,也可以使用PIVOT函数来获取结果。根据您的注释,可以定义任意数量的字段,听起来您需要使用动态SQL来获得最终结果。在编写动态SQL版本之前,我总是从查询的静态或硬编码版本开始,然后将其转换为动态SQL。
除了使用这些方法之外,我还建议使用窗口函数row_number()
为userid
和fieldname
的每个组合生成唯一值。由于您正在转换字符串值,因此您必须使用max
/ min
聚合函数,该函数将为每个字段名仅返回一个值,通过添加row_number,您将能够返回多个组合每个用户都有Location
等。
如果您使用带有CASE表达式的聚合函数,则查询将为:
select
userid,
max(case when userfieldname = 'Location' then userfieldvalue end) location,
max(case when userfieldname = 'Color' then userfieldvalue end) Color
from
(
select v.userid,
f.userfieldname,
v.userfieldvalue,
row_number() over(partition by v.userid, v.userfieldid
order by v.userfieldid) seq
from userFields f
left join userValues v
on f.userfieldId = v.userFieldId
) d
group by userid, seq
order by userid;
如果您使用的是PIVOT,则查询的硬编码版本为:
select userid, Location, Color
from
(
select v.userid,
f.userfieldname,
v.userfieldvalue,
row_number() over(partition by v.userid, v.userfieldid
order by v.userfieldid) seq
from userFields f
left join userValues v
on f.userfieldId = v.userFieldId
) d
pivot
(
max(userfieldvalue)
for userfieldname in (Location, Color)
) p
order by userid;
一旦拥有了正确的逻辑,就可以将PIVOT转换为要执行的动态SQL:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(UserFieldName)
from UserFields
group by UserFieldName, userfieldId
order by userfieldid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT userid, ' + @cols + '
from
(
select v.userid,
f.userfieldname,
v.userfieldvalue,
row_number() over(partition by v.userid, v.userfieldid
order by v.userfieldid) seq
from userFields f
left join userValues v
on f.userfieldId = v.userFieldId
) x
pivot
(
max(userfieldvalue)
for userfieldname in (' + @cols + ')
) p
order by userid'
execute sp_executesql @query;
见SQL Fiddle with Demo。所有版本都会给出结果:
| USERID | LOCATION | COLOR |
|--------|----------|--------|
| 1 | Home | Orange |
| 1 | Office | (null) |
| 2 | Office | Red |