我有一张桌子
CREATE TABLE [dbo].[newTable](
[EBELN] [nvarchar](20) NOT NULL,
[EBELP] [nvarchar](10) NOT NULL,
[VGABE] [nvarchar](2) NOT NULL,
[MENGE] [numeric](15, 3) NULL,
[DMBTR] [numeric](15, 2) NULL
)
它有这些记录
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0001', '1', 1 , 27.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0001', '2', 1 , 27.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0002', '1', 1 , 10.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000004', '0002', '2', 1 , 10.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0001', '1', 1 , 22.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0001', '2', 1 , 22.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0002', '1', 1 , 32.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('3000000010', '0002', '2', 1 , 32.95 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0001', '1', 1 , 400.00 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0001', '1', 1 , 400.00 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0001', '2', 1 , 400.00 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0002', '1', 1 , 200.00 )
Go
insert into dbo.newTable(EBELN, EBELP, VGABE, MENGE , DMBTR) values('4151516119', '0002', '2', 1 , 200.00 )
Go
这就是SELECT *
EBELN EBELP VGABE MENGE DMBTR
-------------------- ---------- ----- -------------- ---------------------------------------
3000000004 0001 1 1.000 27.95
3000000004 0001 2 1.000 27.95
3000000004 0002 1 1.000 10.95
3000000004 0002 2 1.000 10.95
3000000010 0001 1 1.000 22.95
3000000010 0001 2 1.000 22.95
3000000010 0002 1 1.000 32.95
3000000010 0002 2 1.000 32.95
4151516119 0001 1 1.000 400.00
4151516119 0001 1 1.000 400.00
4151516119 0001 2 1.000 400.00
4151516119 0002 1 1.000 200.00
4151516119 0002 2 1.000 200.00
3000000004 0001 2 1.000 27.95
3000000004 0002 1 1.000 10.95
3000000004 0002 2 1.000 10.95
3000000010 0001 1 1.000 22.95
3000000010 0001 2 1.000 22.95
3000000010 0002 1 1.000 32.95
3000000010 0002 2 1.000 32.95
4151516119 0001 1 1.000 400.00
4151516119 0001 1 1.000 400.00
4151516119 0001 2 1.000 400.00
4151516119 0002 1 1.000 200.00
4151516119 0002 2 1.000 200.00
4151516177 0002 6 1.000 111.00
4151516177 0002 8 1.000 111.00
我需要和想要的是一个生成此结果的动态轴
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| EBELN | EBELP | c_DMBTR_1 | c_MENGE_1 | c_DMBTR_2 | c_MENGE_2 | c_DMBTR_6 | c_MENGE_6 | c_DMBTR_8 | c_MENGE_8 |
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
| 3000000004 | 0001 | 27.95 | 1 | 27.95 | 1 | NULL | NULL | NULL | NULL |
| 3000000004 | 0002 | 10.95 | 1 | 10.95 | 1 | NULL | NULL | NULL | NULL |
| [...] | | | | | | | | | |
| 4151516119 | 0001 | 800.00 | 1 | 400.00 | 1 | NULL | NULL | NULL | NULL |
| 4151516177 | 0002 | NULL | NULL | NULL | NULL | 111.00 | 1 | 111.00 | 1 |
+------------+-------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
我尝试了几种解决方案,但没有人得到我想要的结果。
我需要的是VGABE
中要(1,2,6,7,8,9,P,R)
连接到c_DMBTR
和c_MENGE
的字符串名称的值。但是可能的是,例如P或7没有被使用,所以我不希望有这样的列。我认为让它变得动态是唯一可行的方法。
来自VGABE
的值应添加到列名称'c_MENGE_'+VGABE
中,并且必须按顺序排列,这意味着它必须以VGABE
中包含所有列的最低值开头然后是下一个值,直到vgabe的每个使用值。
如果有一个位置(EBELP
)来自VGABE
的多个值,就像POS 0001
的两倍1,正如您在EBELN 4151516119
所看到的那样我必须此位置的SUM(DMBTR)和VGABE值。我和MENGE一样。
是否可以在一个查询或存储过程中执行。我不知道如何得到这个结果,我现在被卡住了。或者还有另一种我不知道的方法吗?
答案 0 :(得分:2)
为了获得您想要的最终结果,您首先必须unpivot
DMBTR
和MENGE
列,然后应用PIVOT
函数进行转换行成列。
你没有提到你正在使用哪个版本的SQL Server我会猜测SQL Server 2005+。从SQL Server 2005开始,PIVOT功能已经可用,但对于UNPIVOT,你也可以使用CROSS APPLY - 我认为这在这里会更容易。
在深入研究动态SQL版本之前,我总是希望编写一个静态版本来获取逻辑,然后将其转换为动态SQL。第一步是将DMBTR
和MENGE
列转换为行:
select
t.ebeln,
t.ebelp,
new_col = c.orig_col + '_' + vgabe,
c.value
from dbo.newTable t
cross apply
(
select 'c_MENGE', menge union all
select 'c_DMBTR', dmbtr
) c (orig_col, value);
见SQL Fiddle with Demo。这会将您的数据转换为:
| EBELN | EBELP | NEW_COL | VALUE |
|------------|-------|-----------|-------|
| 3000000004 | 0001 | c_MENGE_1 | 1 |
| 3000000004 | 0001 | c_DMBTR_1 | 27.95 |
| 3000000004 | 0001 | c_MENGE_2 | 1 |
| 3000000004 | 0001 | c_DMBTR_2 | 27.95 |
| 3000000004 | 0002 | c_MENGE_1 | 1 |
| 3000000004 | 0002 | c_DMBTR_1 | 10.95 |
正如您所看到的,您现在有多行,以及new_col
的连接值c_MENGE_1
等等,这将是您的最终列。
获得此结果后,您可以应用PIVOT功能:
select ebeln,
ebelp,
c_DMBTR_1, c_MENGE_1, c_DMBTR_2, c_MENGE_2,
c_DMBTR_6, c_MENGE_6, c_DMBTR_8, c_MENGE_8
from
(
select
t.ebeln,
t.ebelp,
new_col = c.orig_col + '_' + vgabe,
c.value
from dbo.newTable t
cross apply
(
select 'c_MENGE', menge union all
select 'c_DMBTR', dmbtr
) c (orig_col, value)
) d
pivot
(
sum(value)
for new_col in (c_DMBTR_1, c_MENGE_1, c_DMBTR_2, c_MENGE_2,
c_DMBTR_6, c_MENGE_6, c_DMBTR_8, c_MENGE_8)
) piv
order by ebeln, ebelp;
现在你已经有了正确的逻辑,你需要将它转换为动态SQL。这将首先创建新列名的sql字符串。为此,您将使用FOR XML PATH
:
select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + vgabe)
from dbo.NewTable t
cross apply
(
select 'c_DMBTR', 1 union all
select 'c_MENGE', 2
) c (col, so)
group by col, so, vgabe
order by vgabe, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
这类似于我在静态版本中使用的代码。它获取vgabe
值的列表,并将其连接到您想要PIVOT(DMBTR
,MENGE
)的2列的名称。我还为这些列提供了排序顺序,因此您可以根据需要订购它们。完整的动态SQL代码将是:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(col + '_' + vgabe)
from dbo.NewTable t
cross apply
(
select 'c_DMBTR', 1 union all
select 'c_MENGE', 2
) c (col, so)
group by col, so, vgabe
order by vgabe, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query
= 'SELECT ebeln, ebelp,' + @cols + N'
from
(
select
t.ebeln,
t.ebelp,
new_col = c.orig_col + ''_'' + vgabe,
c.value
from dbo.newTable t
cross apply
(
select ''c_MENGE'', menge union all
select ''c_DMBTR'', dmbtr
) c (orig_col, value)
) x
pivot
(
sum(value)
for new_col in (' + @cols + N')
) p
order by ebeln, ebelp'
exec sp_executesql @query;
见SQL Fiddle with Demo。这给出了一个结果:
| EBELN | EBELP | C_DMBTR_1 | C_MENGE_1 | C_DMBTR_2 | C_MENGE_2 | C_DMBTR_6 | C_MENGE_6 | C_DMBTR_8 | C_MENGE_8 |
|------------|-------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|-----------|
| 3000000004 | 0001 | 27.95 | 1 | 27.95 | 1 | (null) | (null) | (null) | (null) |
| 3000000004 | 0002 | 10.95 | 1 | 10.95 | 1 | (null) | (null) | (null) | (null) |
| 3000000010 | 0001 | 22.95 | 1 | 22.95 | 1 | (null) | (null) | (null) | (null) |
| 3000000010 | 0002 | 32.95 | 1 | 32.95 | 1 | (null) | (null) | (null) | (null) |
| 4151516119 | 0001 | 800 | 2 | 400 | 1 | (null) | (null) | (null) | (null) |
| 4151516119 | 0002 | 200 | 1 | 200 | 1 | 111 | 1 | 111 | 1 |