动态创建列sql
Posted
技术标签:
【中文标题】动态创建列sql【英文标题】:Dynamically create columns sql 【发布时间】:2012-09-20 12:31:45 【问题描述】:我有一张客户表
Customer ID Name
1 John
2 Lewis
3 Mary
我有另一张表 CustomerRewards
TypeID Description
1 Bronze
2 Silver
3 Gold
4 Platinum
5 AnotherOne
决赛桌
RewardID TypeID CustomerID
1 1 1
2 1 1
3 2 1
4 2 2
customerTypes 表是动态的,其中许多类型可以添加和删除。基本上我想要的只是动态生成的列和每个列的计数,比如
CustomerName Bronze Silver Gold Platinum AnotherOne total
John 2 1 0 0 0 3
Lewis 0 1 0 0 0 1
Grand TOTAL 2 2 0 0 0 4
问题就像我说的那样,类型是动态的,客户是动态的,所以我需要根据系统中的类型动态列
我已经在 DataGridView 中标记了 c#,因为我需要它
提前致谢
【问题讨论】:
这看起来像一个支点。我已经做了一些,但我无法从记忆中输入一个。也许是通过在 SQL 端旋转数据创建的数据库中的视图? 如果您需要在 SQL 中执行此操作,您可能需要动态数据透视。参见,例如,simple-talk.com/blogs/2007/09/14/… 但这并不是一个真正干净的解决方案。如果您可以等待将数据导入 C#,您可以使用 LINQ 来执行此操作。 这些看起来确实很复杂!感谢 cmets,我会研究 Pivot,但如果有人有简单的解决方案,请随意 SQL Server dynamic PIVOT query?的可能重复 【参考方案1】:您需要为此使用PIVOT
函数。如果您有已知数量的列,那么您可以对这些值进行硬编码:
select name, [Bronze], [Silver], [Gold], [Platinum], [AnotherOne]
from
(
select c.name,
cr.description,
r.typeid
from customers c
left join rewards r
on c.id = r.customerid
left join customerrewards cr
on r.typeid = cr.typeid
) x
pivot
(
count(typeid)
for description in ([Bronze], [Silver], [Gold], [Platinum], [AnotherOne])
) p;
见SQL Fiddle with Demo。
现在如果你有未知数量的列,那么你可以使用动态 SQL 来PIVOT
:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(description)
from customerrewards
group by description, typeid
order by typeid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT name,' + @cols + ' from
(
select c.name,
cr.description,
r.typeid
from customers c
left join rewards r
on c.id = r.customerid
left join customerrewards cr
on r.typeid = cr.typeid
) x
pivot
(
count(typeid)
for description in (' + @cols + ')
) p '
execute(@query)
见SQL Fiddle With Demo
如果您需要包含Total
列,则可以使用ROLLUP
(Static Version Demo):
select name, sum([Bronze]) Bronze, sum([Silver]) Silver,
sum([Gold]) Gold, sum([Platinum]) Platinum, sum([AnotherOne]) AnotherOne
from
(
select name, [Bronze], [Silver], [Gold], [Platinum], [AnotherOne]
from
(
select c.name,
cr.description,
r.typeid
from customers c
left join rewards r
on c.id = r.customerid
left join customerrewards cr
on r.typeid = cr.typeid
) x
pivot
(
count(typeid)
for description in ([Bronze], [Silver], [Gold], [Platinum], [AnotherOne])
) p
) x
group by name with rollup
动态版(Demo):
DECLARE @cols AS NVARCHAR(MAX),
@colsRollup AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(description)
from customerrewards
group by description, typeid
order by typeid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select @colsRollup
= STUFF((SELECT ', Sum(' + QUOTENAME(description) + ') as '+ QUOTENAME(description)
from customerrewards
group by description, typeid
order by typeid
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= 'SELECT name, '+ @colsRollup + '
FROM
(
SELECT name,' + @cols + ' from
(
select c.name,
cr.description,
r.typeid
from customers c
left join rewards r
on c.id = r.customerid
left join customerrewards cr
on r.typeid = cr.typeid
) x
pivot
(
count(typeid)
for description in (' + @cols + ')
) p
) x1
GROUP BY name with ROLLUP'
execute(@query)
【讨论】:
你有一个 SQL 注入缺陷/可用性错误: = STUFF((SELECT ', Sum(' + QUOTENAME(description) + ') as '+ description 应该是: = STUFF((SELECT ', Sum(' + QUOTENAME(description) + ') as '+ QUOTENAME(description) 否则,这是一个很棒的帖子! @shellster 是的,你是对的。我更新了我的代码。感谢您了解这一点。以上是关于动态创建列sql的主要内容,如果未能解决你的问题,请参考以下文章