有几种不同的方法可以获得结果,可以使用带有 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;
见SQL Fiddle with Demo
如果您使用 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;
见SQL Fiddle with Demo。
一旦你有了正确的逻辑,你就可以将 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 |