我有一个像这样的SQL Server 2008 Express表:
rno gid uid dat origamt disamt
-----------------------------------------------
1 AA a 12-05-2016 200 210
2 AA b 12-05-2016 300 305
3 AA c 12-05-2016 150 116
4 BB a 12-05-2016 120 125
5 BB c 12-05-2016 130 136
6 CC a 12-05-2016 112 115
7 CC b 12-05-2016 135 136
不同日期的等等
我想这样表现出来:
sno dat gid a_orig a_dis b_orig b_dis c_orig c_dis .....
1 12-05-2016 AA 200 210 300 305 150 116
2 12-05-2016 BB 120 125 0 0 130 136
3 12-05-2016 CC 112 115 135 136 0 0
注意:uid的值不是固定的,它们可能会动态变化,因此,a_orig,a_dis,b_orig,b_dis等不能硬编码到SQL中。
注意:由于gid和uid的笛卡尔积,预计每个日期约有300行。我会通过实现LIKE子句来搜索日期,因为dat
列的数据类型是varchar(50)
。
注意:我希望origamt
和disamt
的数据类型为varchar(50)
而不是Decimal(18, 0)
,但这不是强制性的。
我尝试使用PIVOT,参考stackoverflow和其他网站上发布的几篇文章,但无法完成工作。
以下是我尝试过的内容,使用固定的uid得到了几乎所有的结果,并且仅获取了origamt
:
select *
from
(
select gid, uid, dat, origamt
from vamounts
) as src
pivot
(
sum(origamt)
for uid IN ( a, b )
) as piv;
请帮助我解决此问题最简单的解决方案。我会更喜欢最少的代码行和最少的复杂性。
答案 0 :(得分:2)
Errr,不。您无法使用SQL生成所需的表。这不是一个有效的数据透视表。
" uid的值不固定,它们可能会动态变化,因此, a_orig,a_dis,b_orig,b_dis等不能硬编码到SQL中。"
抱歉,这也是不可能的。您必须指定要作为列标题放置的确切值。无论何时编写SELECT
语句,都必须指定要返回的列(字段)的名称。没有办法解决这个问题。
但是,以下是创建"有效"所需的步骤。数据中的SQL Server数据透视表:
我必须承认,当我最近不得不在SQL Server中编写我的第一个PIVOT
时,我也像疯了一样搜索,但不知道如何编写它。
但是,我最终得出了你需要做的事情,所以这里是你在其他任何地方都找不到的循序渐进的指南......!
(读者可以轻松调整这些说明,与您自己的数据一起使用!)
<强> 1。创建示例数据
如果您希望读者回复您的问题,您至少应该为他们提供SQL来创建您的示例数据,这样他们就可以解决这些问题。
所以,这里是我如何创建问题中显示的数据:
CREATE TABLE tblSomething
(
[gid] nvarchar(100),
[uid] nvarchar(100),
[dat] datetime,
[origamt] int,
[disamt] int
)
GO
INSERT INTO tblSomething VALUES ('AA', 'a', '2016-05-12', 200, 210)
INSERT INTO tblSomething VALUES ('AA', 'b', '2016-05-12', 300, 305)
INSERT INTO tblSomething VALUES ('AA', 'c', '2016-05-12', 150, 116)
INSERT INTO tblSomething VALUES ('BB', 'a', '2016-05-12', 120, 125)
INSERT INTO tblSomething VALUES ('BB', 'c', '2016-05-12', 130, 136)
INSERT INTO tblSomething VALUES ('CC', 'a', '2016-05-12', 112, 115)
INSERT INTO tblSomething VALUES ('CC', 'b', '2016-05-12', 135, 136)
GO
<强> 2。编写一个SQL查询,它只返回三列
第一列将包含将出现在PIVOT表的左栏中的值。
第二列将包含将出现在顶行的值列表。
第三列中的值将根据行/列标题定位在PIVOT表中。
好的,这是执行此操作的SQL:
SELECT [gid], [uid], [origamt]
FROM tblSomething
这是使用PIVOT
的关键。您的数据库结构可能非常复杂,但使用PIVOT
时,您只能使用三个值。不多也不少。
所以,这就是SQL将返回的内容。我们的目标是创建一个包含(仅)这些值的PIVOT表:
第3。查找标题行的不同值列表
请注意,在我想要创建的数据透视表中,我有三个名为a
,b
和c
的列(字段)。这是您[uid]
列中的三个唯一值。
因此,要获得这些唯一值的逗号连接列表,我可以使用此SQL:
DECLARE @LongString nvarchar(4000)
SELECT @LongString = COALESCE(@LongString + ', ', '') + '[' + [uid] + ']'
FROM [tblSomething]
GROUP BY [uid]
SELECT @LongString AS 'Subquery'
当我针对您的数据运行此操作时,我得到的是:
现在,剪切并粘贴此值:我们需要在整个SQL SELECT命令中两次来创建数据透视表。
<强> 4。全部放在一起
这是一个棘手的问题。
您需要将步骤2中的SQL命令和步骤3的结果合并为一个SELECT
命令。
这是你的SQL的样子:
SELECT [gid],
-- Here's the "Subquery" from part 3
[a], [b], [c]
FROM (
-- Here's the original SQL "SELECT" statement from part 2
SELECT [gid], [uid], [origamt]
FROM tblSomething
) tmp ([gid], [uid], [origamt])
pivot (
MAX([origamt]) for [uid] in (
-- Here's the "Subquery" from part 3 again
[a], [b], [c]
)
) p
...这里有一个令人困惑的图像,它显示了组件的来源以及运行此命令的结果。
正如您所看到的,关键是第2步中的SELECT
语句,并将您选择的三个字段放在此命令的正确位置。
而且,正如我之前所说,数据透视表中的列(字段)来自第3步中获得的值:
[a], [b], [c]
当然,您可以使用这些值的子集。也许您只想查看[a], [b]
的PIVOT值并忽略[c]
。
P!
那么,这就是如何从数据中创建数据透视表。
我更喜欢最少的代码行和最少的复杂性。
是的,祝你好运.. !!!
<强> 5。合并两个数据透视表
如果你真的想要,你可以合并两个这样的PIVOT表的内容,以获得你正在寻找的确切结果。
对于Shobhit来说这很容易写自己的SQL。
答案 1 :(得分:0)
加入可能有帮助
declare @t table (rno int, gid varchar(2), uid varchar(1), dat varchar(10), origamt int, disamt int)
insert into @t
values
(1, 'AA', 'a', '12-05-2016', 200, 210),
(2 , 'AA', 'b', '12-05-2016', 300, 305),
(3 , 'AA', 'c', '12-05-2016', 150, 116),
(4 , 'BB', 'a', '12-05-2016', 120, 125),
(5 , 'BB', 'c', '12-05-2016', 130, 136),
(6 , 'CC', 'a', '12-05-2016', 112, 115),
(7 , 'CC', 'b', '12-05-2016', 135, 136)
select -- piv.*,piv2.*
piv.gid,piv.dat
,piv.a as a_org
,piv2.a as a_dis
,piv.b as b_org
,piv2.b as b_dis
,piv.c as c_org
,piv2.c as c_dis
from
(
select gid, uid, dat, origamt
from @t
) as src
pivot
(
sum(origamt)
for uid IN ([a],[b],[c] )
) as piv
join
(select piv2.*
from
(
select gid, uid, dat, disamt
from @t
) as src
pivot
(
sum(disamt)
for uid IN ([a],[b],[c] )
) as piv2
) piv2
on piv2.gid = piv.gid and piv2.dat = piv.dat
这是一个POC,你必须使用动态sql来处理可变数量的uid。如果您不知道如何使用动态SQL,请告诉我,我会为您编写一个示例。
答案 2 :(得分:0)
这个东西需要动态 SQL。
首先使用您的数据创建表格:
CREATE TABLE #temp (
rno int,
gid nvarchar(10),
[uid] nvarchar(10),
dat date,
origamt int,
disamt int
)
INSERT INTO #temp VALUES
(1, 'AA', 'a', '12-05-2016', 200, 210),
(2, 'AA', 'b', '12-05-2016', 300, 305),
(3, 'AA', 'c', '12-05-2016', 150, 116),
(4, 'BB', 'a', '12-05-2016', 120, 125),
(5, 'BB', 'c', '12-05-2016', 130, 136),
(6, 'CC', 'a', '12-05-2016', 112, 115),
(7, 'CC', 'b', '12-05-2016', 135, 136)
然后使用列声明变量:
DECLARE @columns nvarchar(max), @sql nvarchar(max), @columns1 nvarchar(max), @columnsN nvarchar(max)
--Here simple columns like [a],[b],[c] etc
SELECT @columns =STUFF((SELECT DISTINCT ','+QUOTENAME([uid]) FROM #temp FOR XML PATH('')),1,1,'')
--Here with ISNULL operation ISNULL([a],0) as [a],ISNULL([b],0) as [b],ISNULL([c],0) as [c]
SELECT @columnsN = STUFF((SELECT DISTINCT ',ISNULL('+QUOTENAME([uid])+',0) as '+QUOTENAME([uid]) FROM #temp FOR XML PATH('')),1,1,'')
--Here columns for final table orig.a as a_orig, dis.a as a_dis,orig.b as b_orig, dis.b as b_dis,orig.c as c_orig, dis.c as c_dis
SELECT @columns1 = STUFF((SELECT DISTINCT ',orig.'+[uid] + ' as ' +[uid]+ '_orig, dis.'+[uid] + ' as ' +[uid]+ '_dis' FROM #temp FOR XML PATH('')),1,1,'')
主要查询:
SELECT @sql = '
SELECT orig.gid,
orig.dat,
'+@columns1+'
FROM (
SELECT gid, dat, '+@columnsN+'
FROM (
SELECT gid, [uid], LEFT(dat,10) as dat, origamt
FROM #temp
) as p
PIVOT (
SUM(origamt) FOR [uid] in ('+@columns+')
) as pvt
) as orig
LEFT JOIN (
SELECT gid, dat, '+@columnsN+'
FROM (
SELECT gid, [uid], LEFT(dat,10) as dat, disamt
FROM #temp
) as p
PIVOT (
SUM(disamt) FOR [uid] in ('+@columns+')
) as pvt
) as dis
ON dis.gid = orig.gid and dis.dat = orig.dat'
EXEC(@sql)
输出:
gid dat a_orig a_dis b_orig b_dis c_orig c_dis
AA 2016-12-05 200 210 300 305 150 116
BB 2016-12-05 120 125 0 0 130 136
CC 2016-12-05 112 115 135 136 0 0