Pivot/transpose 多列有效地将行转化为列
Pivot/transpose rows into columns efficiently with multiple columns
假设我有这样的数据:
Table
Num1 Type1 Code Group DA Account Value
1X2 GG XX1 INTS 1 123 75.00
1X2 GG XX1 INTS 1 234 100.00
我想做的是旋转数据,使其看起来像这样:
Num1 Type1 Code Group DA 123 234
1X2 GG XX1 INTS 1 75.00 100.00
我不太确定如何使用 PIVOT 完成这样的事情,但我确实尝试了以下方法:
Select Num1,
Type1,
Code,
Group,
DA,
'123' = (Select Value from Table t2 where t1.num1 = t2.num1 and Account = 123 ),
'234' = (Select Value from Table t2 where t1.num1 = t2.num1 and Account = 234 )
From Table t1
但是我得到的错误是:Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
在这种情况下,我向每个子查询添加了“Top 1”:
Select Num1,
Type1,
Code,
Group,
DA,
'123' = (Select TOP 1 Value from Table t2 where t1.num1 = t2.num1 and Account = 123 ),
'234' = (Select TOP 1 Value from Table t2 where t1.num1 = t2.num1 and Account = 234 )
From Table t1
然而,即使现在查询 returns 两行,每个帐户都有 AMOUNTS,我还没有完全理解 TOP 1 的目的,但基本上现在的数据是这样的:
Num1 Type1 Code Group DA 123 234
1X2 GG XX1 INTS 1 NULL 100.00
1X2 GG XX1 INTS 1 75.00 NULL
而且我想这还不错,因为我可以在所有其他列上使用 GROUP BY
执行 MAX(123)
和 MAX(234)
,最后得到 1 行。
有更好的方法吗?这可以通过 PIVOT 实现吗?
SELECT
[Num1],
[Type1],
[Code],
[Group],
[DA],
[123],
[234]
FROM
yourTable
PIVOT
(
MAX([value])
FOR [account] IN ([123], [234])
)
AS PivotTable
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=7fbe16b9254aa5ee60a23e43eec9597f
这个问题是要对数据进行透视需要聚合。在此,您的列的值 value
:
SELECT Num1,
Type1,
Code,
[Group], --GROUP is a reserved keyword and should not be used to object names
DA,
MAX(CASE Account WHEN 123 THEN [Value] END) AS [123],
MAX(CASE Account WHEN 234 THEN [Value] END) AS [234]
FROM dbo.Table t1
GROUP BY Num1,
Type1,
Code,
[Group], --GROUP is a reserved keyword and should not be used to object names
DA;
MatBailie 和 Larnu 100% 正确!但是,如果您需要动态执行此操作(例如,您不知道要汇总的帐户数量),则可以使用动态 SQL。下面提供了您示例的语法:
IF OBJECT_ID('tempdb..#acct_list') IS NOT NULL DROP TABLE #acct_list; -- Deletes #acct_list temp table if it already exists
SELECT DISTINCT ROW_NUMBER() OVER(ORDER BY Account) rownum, Account -- Lists each account with a row number for looping
INTO #acct_list -- Creates and inserts data into a #acct_list temp table
FROM Table
ORDER BY Account;
DECLARE @col INT = 1; -- Counter value used to keep track of which account is being aggregated
DECLARE @cnt INT = (SELECT COUNT(DISTINCT Account) FROM Table); -- Counts the number of unique accounts
DECLARE @sql NVARCHAR(MAX) = N'SELECT Num1, Type1, Code, [Group], DA'; -- Writes the SQL string to be executed
WHILE @col <= @cnt -- Loops through columns until no more exist
BEGIN
-- Identifies the current account
DECLARE @acct VARCHAR(3) = (SELECT Account FROM #acct_list WHERE rownum = @col);
-- Writes SQL syntax for the current account column
SET @sql += ' ,MAX(CASE Account WHEN ''' + @acct + ''' THEN Value END) [' + @acct + ']'
-- Increment the counter to advance to the next column
SET @col += 1;
END;
SET @sql += ' FROM Table GROUP BY Num1, Type1, Code, [Group], DA'
--PRINT @sql
EXEC SYS.SP_EXECUTESQL @sql;
为此你需要像 MAX 和 GROUP BY 这样的聚合函数
CREATE TABLE Table1
([Num1] varchar(3), [Type1] varchar(2), [Code] varchar(3), [Group] varchar(4), [DA] int, [Account] int, [Value] DECIMAL(10,2))
;
INSERT INTO Table1
([Num1], [Type1], [Code], [Group], [DA], [Account], [Value])
VALUES
('1X2', 'GG', 'XX1', 'INTS', 1, 123, 75.00),
('1X2', 'GG', 'XX1', 'INTS', 1, 234, 100.00)
;
GO
SELECT
[Num1], [Type1], [Code], [Group],
MAX(CASE WHEN [Account] = 123 THEN [Value] ELSe -999999999999 END) AS [123],
MAX(CASE WHEN [Account] = 234 THEN [Value] ELSe -9999999999 END) AS [234]
FROM Table1
GROUP BY [Num1], [Type1], [Code], [Group]
GO
Num1 | Type1 | Code | Group | 123 | 234
:--- | :---- | :--- | :---- | ----: | -----:
1X2 | GG | XX1 | INTS | 75.00 | 100.00
db<>fiddle here
假设我有这样的数据:
Table
Num1 Type1 Code Group DA Account Value
1X2 GG XX1 INTS 1 123 75.00
1X2 GG XX1 INTS 1 234 100.00
我想做的是旋转数据,使其看起来像这样:
Num1 Type1 Code Group DA 123 234
1X2 GG XX1 INTS 1 75.00 100.00
我不太确定如何使用 PIVOT 完成这样的事情,但我确实尝试了以下方法:
Select Num1,
Type1,
Code,
Group,
DA,
'123' = (Select Value from Table t2 where t1.num1 = t2.num1 and Account = 123 ),
'234' = (Select Value from Table t2 where t1.num1 = t2.num1 and Account = 234 )
From Table t1
但是我得到的错误是:Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
在这种情况下,我向每个子查询添加了“Top 1”:
Select Num1,
Type1,
Code,
Group,
DA,
'123' = (Select TOP 1 Value from Table t2 where t1.num1 = t2.num1 and Account = 123 ),
'234' = (Select TOP 1 Value from Table t2 where t1.num1 = t2.num1 and Account = 234 )
From Table t1
然而,即使现在查询 returns 两行,每个帐户都有 AMOUNTS,我还没有完全理解 TOP 1 的目的,但基本上现在的数据是这样的:
Num1 Type1 Code Group DA 123 234
1X2 GG XX1 INTS 1 NULL 100.00
1X2 GG XX1 INTS 1 75.00 NULL
而且我想这还不错,因为我可以在所有其他列上使用 GROUP BY
执行 MAX(123)
和 MAX(234)
,最后得到 1 行。
有更好的方法吗?这可以通过 PIVOT 实现吗?
SELECT
[Num1],
[Type1],
[Code],
[Group],
[DA],
[123],
[234]
FROM
yourTable
PIVOT
(
MAX([value])
FOR [account] IN ([123], [234])
)
AS PivotTable
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=7fbe16b9254aa5ee60a23e43eec9597f
这个问题是要对数据进行透视需要聚合。在此,您的列的值 value
:
SELECT Num1,
Type1,
Code,
[Group], --GROUP is a reserved keyword and should not be used to object names
DA,
MAX(CASE Account WHEN 123 THEN [Value] END) AS [123],
MAX(CASE Account WHEN 234 THEN [Value] END) AS [234]
FROM dbo.Table t1
GROUP BY Num1,
Type1,
Code,
[Group], --GROUP is a reserved keyword and should not be used to object names
DA;
MatBailie 和 Larnu 100% 正确!但是,如果您需要动态执行此操作(例如,您不知道要汇总的帐户数量),则可以使用动态 SQL。下面提供了您示例的语法:
IF OBJECT_ID('tempdb..#acct_list') IS NOT NULL DROP TABLE #acct_list; -- Deletes #acct_list temp table if it already exists
SELECT DISTINCT ROW_NUMBER() OVER(ORDER BY Account) rownum, Account -- Lists each account with a row number for looping
INTO #acct_list -- Creates and inserts data into a #acct_list temp table
FROM Table
ORDER BY Account;
DECLARE @col INT = 1; -- Counter value used to keep track of which account is being aggregated
DECLARE @cnt INT = (SELECT COUNT(DISTINCT Account) FROM Table); -- Counts the number of unique accounts
DECLARE @sql NVARCHAR(MAX) = N'SELECT Num1, Type1, Code, [Group], DA'; -- Writes the SQL string to be executed
WHILE @col <= @cnt -- Loops through columns until no more exist
BEGIN
-- Identifies the current account
DECLARE @acct VARCHAR(3) = (SELECT Account FROM #acct_list WHERE rownum = @col);
-- Writes SQL syntax for the current account column
SET @sql += ' ,MAX(CASE Account WHEN ''' + @acct + ''' THEN Value END) [' + @acct + ']'
-- Increment the counter to advance to the next column
SET @col += 1;
END;
SET @sql += ' FROM Table GROUP BY Num1, Type1, Code, [Group], DA'
--PRINT @sql
EXEC SYS.SP_EXECUTESQL @sql;
为此你需要像 MAX 和 GROUP BY 这样的聚合函数
CREATE TABLE Table1 ([Num1] varchar(3), [Type1] varchar(2), [Code] varchar(3), [Group] varchar(4), [DA] int, [Account] int, [Value] DECIMAL(10,2)) ; INSERT INTO Table1 ([Num1], [Type1], [Code], [Group], [DA], [Account], [Value]) VALUES ('1X2', 'GG', 'XX1', 'INTS', 1, 123, 75.00), ('1X2', 'GG', 'XX1', 'INTS', 1, 234, 100.00) ;
GO
SELECT [Num1], [Type1], [Code], [Group], MAX(CASE WHEN [Account] = 123 THEN [Value] ELSe -999999999999 END) AS [123], MAX(CASE WHEN [Account] = 234 THEN [Value] ELSe -9999999999 END) AS [234] FROM Table1 GROUP BY [Num1], [Type1], [Code], [Group] GO
Num1 | Type1 | Code | Group | 123 | 234 :--- | :---- | :--- | :---- | ----: | -----: 1X2 | GG | XX1 | INTS | 75.00 | 100.00
db<>fiddle here