我生成了一个广泛的视图,它根据不同的统计模型模拟某些事件。这些模型在每个列标题中由数字定义,行的最大值是最佳模型。
生成的表格(部分)如下所示;
+--------+----+------+------+------+------+------+------+
| Number | LI | PHSE | 0505 | 0506 | 0507 | 0508 | 0509 | [...] etc.
+--------+----+------+------+------+------+------+------+
| 100254 | 2 | M1 | 44 | 46 | 45 | 44 | 44 |
| 100254 | 2 | M2 | 36 | 36 | 35 | 37 | 37 |
| 100254 | 2 | M3 | 5 | 5 | 5 | 5 | 5 |
| 100254 | 2 | R1 | 34 | 36 | 37 | 37 | 37 |
| 100254 | 2 | R2 | 41 | 41 | 40 | 41 | 41 |
| 100329 | 1 | M1 | 37 | 38 | 38 | 38 | 39 |
| 100329 | 1 | M2 | 31 | 29 | 28 | 29 | 29 |
| 100329 | 1 | M3 | 6 | 6 | 6 | 6 | 6 |
| 100329 | 1 | R1 | 29 | 29 | 29 | 30 | 30 |
| 100329 | 1 | R2 | 25 | 26 | 26 | 27 | 26 |
+--------+----+------+------+------+------+------+------+
[...] etc.
现在我想找到每个行中的最高值并显示相应的列名称;
| Number | LI | PHSE | MAXCOL |
+--------+----+------+--------+
| 100254 | 2 | M1 | 0506 |
| 100254 | 2 | M2 | 0508 |
| 100254 | 2 | M3 | 0505 |
| 100254 | 2 | R1 | 0507 |
| 100254 | 2 | R2 | 0505 |
+--------+----+------+--------+
[...] etc.
这是从 100254 - 2 - M1 最大值 46 出现在 0506 列等中得出的。
我一直在尝试
PIVOT
功能,但没有成功。我还寻找了类似于 Excel 中的索引/匹配等效项,但由于我无法将列标题作为值引用,这显然不起作用(并且也没有找到这样的函数)。
任何帮助将不胜感激。
根据达米安的评论更新:
导致此结果的代码摘录:
SELECT DISTINCT sub2.Number, sub2.LI, sub2.PHSE
, sum(sub2.[0505]) over (partition by sub2.Number, sub2.LI, sub2.PHSE) as '0505'
, sum(sub2.[0506]) over (partition by sub2.Number, sub2.LI, sub2.PHSE) as '0506'
[...] etc. /*64 rows*/
FROM
(SELECT DISTINCT sub.*
, CASE WHEN sub.MF > sub.[5PAV] - sub.[5PSTDEV] THEN 1 ELSE 0 END AS '0505'
, CASE WHEN sub.MF > sub.[5PAV] - sub.[6PSTDEV] THEN 1 ELSE 0 END AS '0506'
[...] etc. /*64 rows*/
FROM
(SELECT DISTINCT ra.*
, sum(ra.qtyr) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 5 preceding AND 1 preceding) /
sum(ra.qtyu) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 5 preceding AND 1 preceding) AS '5PAV'
, sum(ra.qtyr) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 6 preceding AND 1 preceding) /
sum(ra.qtyu) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 6 preceding AND 1 preceding) AS '6PAV'
[...] etc. /*8 rows*/
, stdev(ra.MF) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 4 preceding AND CURRENT row) AS '5PSTDEV'
, stdev(ra.MF) OVER (partition BY ra.Number, ra.LI, ra.PHSE ORDER BY (ra.Number) rows BETWEEN 5 preceding AND CURRENT row) AS '6PSTDEV'
[...] etc. /*8 rows*/
FROM ra
) AS sub
) AS sub2
毫无疑问,这可能是 SQL 最无效的用法之一,但时间压力和经验不足让我这样写。
任何更改此代码并更有效地实现所需的表格结果的建议也将不胜感激。
根据安东的回答进行编辑;
上面的代码总结为
pvt
继续如下;
SELECT Number, LI, PHSE, combo, hitrate
FROM (...) AS pvt
UNPIVOT
(Hitrate FOR Combo IN (
[0505],
[0506],
[...] etc.)) AS upvt
解决一个不优雅的问题的好方法。
您需要使用 UNPIVOT,而不是 PIVOT
https://msdn.microsoft.com/en-us/library/ms177410.aspx
如果列数可变,则必须使用动态sql来构造列列表
您可以使用 UNPIVOT 和 CROSS APPLY。
使用此解决方案,您不必多次指定所有列。
来源数据:
CREATE TABLE Student
([Name] varchar(5), [Maths] int, [Science] int, [English] int)
;
INSERT INTO Student
([Name], [Maths], [Science], [English])
VALUES
('Tilak', 90, 40, 60),
('Raj', 30, 50, 70)
;
解决方案:
with foo as (
select name, subject, marks
from student
unpivot
(
marks
for subject in (Science, Maths, English)
) u
)
select distinct f1.name, f2.subject
from foo f1
cross apply (
select top 1 name, subject
from foo
where f1.Name = Name
order by Marks desc) f2
结果:
--------------------------------------------------
| Name | Subject
--------------------------------------------------
| Tilak | Maths
--------------------------------------------------
| Raj | Science
--------------------------------------------------
如果您想查看所有 MAXCOL(相等的列),请尝试以下操作:
CREATE TABLE table1 (
Number NUMERIC(10),
LI numeric(10),
PHSE NVARCHAR(10),
[0505] numeric(10),
[0506] numeric(10),
[0507] numeric(10),
[0508] numeric(10),
[0509] numeric(10))
INSERT INTO table1 VALUES(100254,2,'M1',44 ,46 ,45 ,44,44)
INSERT INTO table1 VALUES(100254,2,'M2',36,36,35,37,37)
INSERT INTO table1 VALUES(100254,2,'M3',5,5,5,5,5)
INSERT INTO table1 VALUES(100254,2,'R1',34,36,37,37,37)
INSERT INTO table1 VALUES(100254,2, 'R2',41,41,40,41,41)
INSERT INTO table1 VALUES(100329,1, 'M1',37,38,38,38,39)
INSERT INTO table1 VALUES(100329,1, 'M2',31,29,28,29,29)
INSERT INTO table1 VALUES(100329,1, 'M3',6,6,6,6,6)
INSERT INTO table1 VALUES(100329,1, 'R1',29,29,29,30,30)
INSERT INTO table1 VALUES(100329,1, 'R2',25,26,26,27,26)
SELECT *
INTO #UNPIVOT
FROM table1
UNPIVOT ( num
FOR MAXCOL IN ([0505],[0506],[0507],[0508],[0509])) AS k
SELECT A.Number,A.LI,A.PHSE,A.num,B.MAXCOL FROM
(SELECT number,LI,PHSE,MAX(num) AS num FROM #UNPIVOT GROUP BY number,LI,PHSE) A
LEFT JOIN
(SELECT * FROM #UNPIVOT) B ON A.num=B.num AND A.Number=B.Number AND A.LI=B.LI AND A.PHSE=B.PHSE
我会使用
CROSS APPLY
,如下所示:
WITH Src AS
(
SELECT * FROM (VALUES
(100254, 2, 'M1', 44, 46, 45, 44, 44),
(100254, 2, 'M2', 36, 36, 35, 37, 37),
(100254, 2, 'M3', 5, 5, 5, 5, 5),
(100254, 2, 'R1', 34, 36, 37, 37, 37),
(100254, 2, 'R2', 41, 41, 40, 41, 41),
(100329, 1, 'M1', 37, 38, 38, 38, 39),
(100329, 1, 'M2', 31, 29, 28, 29, 29),
(100329, 1, 'M3', 6, 6, 6, 6, 6),
(100329, 1, 'R1', 29, 29, 29, 30, 30),
(100329, 1, 'R2', 25, 26, 26, 27, 26)) T(Number, LI, PHSE, [0505], [0506], [0507], [0508], [0509])
)
SELECT Number, LI, PHSE, MaxCol
FROM Src
CROSS APPLY (SELECT TOP 1 * FROM (VALUES
('0505', [0505]),
('0506', [0506]),
('0507', [0507]),
('0508', [0508]),
('0509', [0509])
) T(MaxCol, Val) ORDER BY Val DESC) Q
请注意,除非指定了一些附加值,即 MaxCol,否则可以随机选择相等的列。
更新 您需要动态查询,如下所示:
DECLARE @sql nvarchar(MAX) =
'SELECT Number, LI, PHSE, MaxCol
FROM Src
CROSS APPLY (SELECT TOP 1 * FROM (VALUES' +STUFF(
(SELECT ',(', QUOTENAME(name, '''')+','+QUOTENAME(name)+')'
FROM sys.columns
WHERE object_id=OBJECT_ID('Src') AND name NOT IN ('Number', 'LI', 'PHSE')
FOR XML PATH('')), 1, 1, '')+') T(MaxCol, Val) ORDER BY Val DESC) Q';
EXEC(@sql);
Src
是你的表名,相应替换它。