Reputation: 896
Let's say I have data that looks liek this:
Table
Num1 Type1 Code Group DA Account Value
1X2 GG XX1 INTS 1 123 75.00
1X2 GG XX1 INTS 1 234 100.00
What's I'm trying to do is Pivot the data so it looks like this:
Num1 Type1 Code Group DA 123 234
1X2 GG XX1 INTS 1 75.00 100.00
I'm not really sure how something like this can be accomplished with PIVOT, but I did try the below approach:
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
However the error I'm getting is: Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
In that case I added "Top 1" to each subquery:
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
However, even though the query now returns two rows with AMOUNTS for each Account, I'm not fully understanding the purpose of TOP 1, but basically now the data looks like this:
Num1 Type1 Code Group DA 123 234
1X2 GG XX1 INTS 1 NULL 100.00
1X2 GG XX1 INTS 1 75.00 NULL
And I guess that's not bad, because I can do a MAX(123)
and MAX(234)
with GROUP BY
on all the other columns, and end up with 1 row.
Is there a better approach to this? Can this be achieved with PIVOT?
Upvotes: 3
Views: 1211
Reputation: 21
MatBailie and Larnu are 100% correct! However, if you ever need to do this dynamically (e.g. you don't know the number of accounts to be summarized), dynamic SQL can be used. The syntax for your example is provided below:
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;
Upvotes: 1
Reputation: 86775
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
Upvotes: 1
Reputation: 49395
For that you need aggregation Functions Like MAX And a 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
Upvotes: 3
Reputation: 95906
This problem is that to pivot your data you need to aggregate. In this, the value of your column 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;
Upvotes: 1