How to pivot columns in SQL Server - sql-server

I'm new to SQL Server and I am trying to pivot rows into columns
select SalesOrExpense, store_no, total
from myTable
SalesOrExpense Store_No total ($)
-------------------------------------
Expense 22 100
Sales 22 400
to look like this
Store_No Expense Sales
---------------------------------
22 100 400
Could someone help point me in the right direction?
Thanks

We can even do it by executing dynamic sql query..
Query
declare #sql as varchar(max);
select #sql = stuff((
select ', sum(case [SalesOrExpense] when ' + char(39) +
[SalesOrExpense] + char(39) +
' then [total] else 0 end) as [' + [SalesOrExpense] + ']'
from [your_table_name]
for xml path('')
)
, 1, 2, ''
);
select #sql = 'select [Store_No], ' + #sql +
' from [your_table_name] group by [Store_No];';
exec(#sql);

CREATE TABLE #Table1
([SalesOrExpense] varchar(7), [Store_No] int, [total] int)
;
INSERT INTO #Table1
([SalesOrExpense], [Store_No], [total])
VALUES
('Expense', 22, 100),
('Sales', 22, 400)
select *
from
(
select *
from #Table1
) src
pivot
(
max(total)
for SalesOrExpense in ([Expense], [Sales])
) piv;

CREATE TABLE #Table1
([SalesOrExpense] varchar(7), [Store_No] int, [total] int);
INSERT INTO #Table1
([SalesOrExpense], [Store_No], [total])
VALUES
('Expense', 22, 100),
('Sales', 22, 400);
SELECT Store_No,
SUM(CASE WHEN SalesOrExpense='Expense' THEN TOTAL END) AS Expense,
SUM(CASE WHEN SalesOrExpense='Sales' THEN TOTAL END) AS Sales
FROM #table1 GROUP BY Store_No;
OUTPUT:-
-------------------------
Store_No | Expense |Sales
---------------------------
22 100 400

Related

SQL Server error message truncated

This is not an error message about truncation. Rather, the error message itself (from SSMS) appears to have been truncated. Any idea what it was trying to tell me here? Is there a way to recover the full error message?
Msg 203, Level 16, State 2, Line 80
The name 'SELECT
SUM(CASE WHEN #actual_types.typ = 'AA' THEN #actual_types.qty ELSE 0 END) AS 'AA_Qty',
SUM(CASE WHEN #actual_types.typ = 'AB' THEN #actual_types.qty ELSE 0 END) AS 'AB_Qty',
SUM(CASE WHEN #actual_types.typ = 'AC' THEN #actual_types.qty ELSE 0 END) AS 'AC_Qty',
SUM(CASE WHEN #actual_types.typ = 'BA' THEN #actual_types.qty ELSE 0 END) AS 'BA_Qty',
SUM(CASE WHEN #actual_types.typ...
I'm using SSMS 2016, connected to a SQL 2000 server. For context - I was trying to create a more generic version of one of my current scripts (works fine against production data), using temp tables and sample data, to save as a reference in case I should need something similar in the future.
This was the code responsible for the error:
CREATE TABLE #possible_types
(typ varchar(2))
CREATE TABLE #actual_types
(typ varchar(2),
dt smalldatetime,
qty int)
INSERT #possible_types
SELECT 'AA'
UNION SELECT 'AB'
UNION SELECT 'AC'
UNION SELECT 'BA'
UNION SELECT 'BB'
UNION SELECT 'BC'
INSERT #actual_types
SELECT 'AA', '2015-01-01', 123
UNION SELECT 'AA', '2016-01-01', 321
UNION SELECT 'AA', '2017-01-01', 222
UNION SELECT 'BA', '2016-01-01', 777
UNION SELECT 'BC', '2017-01-01', 456
DECLARE #qry varchar(8000)
SELECT #qry = 'SELECT' + CHAR(13)
SELECT #qry = #qry + s.sql_gen
FROM
(SELECT DISTINCT 'SUM(CASE WHEN #actual_types.typ = '''+ typ + ''' THEN #actual_types.qty ELSE 0 END) AS ''' + typ + '_Qty'',' + char(13) AS [sql_gen]
FROM #possible_types) s
SELECT #qry = LEFT(#qry, LEN(#qry) - 2) -- gets rid of last comma and carriage return
SELECT #qry = #qry + '
FROM #actual_types
WHERE #actual_types.dt >= ''2017-01-01''
'
--PRINT #qry
EXEC #qry;
DROP TABLE #possible_types
DROP TABLE #actual_types
Error messages in sql server are stored in sys.messages. You can query the messages table using the information provided.
select * from sys.messages
where message_id = 203
and language_id = 1033 --1033 is English (assumed you can read English)
This returns "The name '%.*ls' is not a valid identifier."
You obviously have something else wonky in your code. Can you share your query and we can probably help determine the actual cause of the issue.
I had the same error. Now it works for me.
I removed the ' for the name of the fields _Qty. (Actually it's not necessary for made your query working).
Moreover I edited:
DECLARE #qry nvarchar(4000)
and
EXECUTE sp_executesql #qry;
Full code edited:
CREATE TABLE #possible_types
(typ varchar(2))
CREATE TABLE #actual_types
(typ varchar(2),
dt smalldatetime,
qty int)
INSERT #possible_types
SELECT 'AA'
UNION SELECT 'AB'
UNION SELECT 'AC'
UNION SELECT 'BA'
UNION SELECT 'BB'
UNION SELECT 'BC'
INSERT #actual_types
SELECT 'AA', '2015-01-01', 123
UNION SELECT 'AA', '2016-01-01', 321
UNION SELECT 'AA', '2017-01-01', 222
UNION SELECT 'BA', '2016-01-01', 777
UNION SELECT 'BC', '2017-01-01', 456
DECLARE #qry nvarchar(4000)
SELECT #qry = 'SELECT' + CHAR(13)
SELECT #qry = #qry + s.sql_gen
FROM
(SELECT DISTINCT 'SUM(CASE WHEN #actual_types.typ = '''+ typ + ''' THEN #actual_types.qty ELSE 0 END) AS ' + typ + '_Qty,' + char(13) AS [sql_gen]
FROM #possible_types) s
SELECT #qry = LEFT(#qry, LEN(#qry) - 2) -- gets rid of last comma and carriage return
SELECT #qry = #qry + '
FROM #actual_types
WHERE dt >= ''2017-01-01''
'
PRINT #qry
EXECUTE sp_executesql #qry;
DROP TABLE #possible_types
DROP TABLE #actual_types

Rows to columns - sql 2008

Just learning SQL - I have the following table:
Site1 Totals
Status1 20
Status2 5
Status3 15
Status4 145
Status5 1
And need to convert the columns and rows, adding a new column name "Server Name" and changing the rows to columns, to return the following:
Server name Status1 Status2 Status3 Status4 Status5
Site1 20 5 15 145 1
Is anyone able to help with this?
Thankyou
select ServerName = 'Site1', *
from
(
select Totals, Site1
from Sometable
) d
pivot
(
max(Totals)
for Site1 in (Status1, Status2, Status3, Status4, Status5)
) piv;
EDIT:
If you need to dynamically load values from Site1 column you can do it this way:
CREATE table #yourtable
([Site1] varchar(20), [Totals] int)
;
INSERT INTO #yourtable
([Site1], [Totals])
VALUES
('Status1', 20),
('Status2', 45),
('Status3', 77),
('Status4', 55)
;
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Site1)
from #yourtable
group by Site1
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ServerName=''Site1'', ' + #cols + N' from
(
select Site1, Totals
from #yourtable
) x
pivot
(
max(Totals)
for Site1 in (' + #cols + N')
) p '
exec sp_executesql #query;
DEMO

Pivot with Group by on SQL

I'm create sql syntax which create pivot Group By Product based on Category
CREATE TABLE #Product ( Product varchar(10),Category varchar(10),Stock int)
INSERT INTO #Product Values ('Item A','CatA',10)
INSERT INTO #Product Values ('Item A','CatB',5)
INSERT INTO #Product Values ('Item B','CatA',3)
INSERT INTO #Product Values ('Item B','CatB',5)
INSERT INTO #Product Values ('Item B','CatC',7)
INSERT INTO #Product Values ('Item B','CatD',10)
SELECT *
FROM
(
SELECT Product,Category,Stock
FROM #Product A
) src
pivot
(
SUM(Stock)
for Category in ([CatA], [CatB], [CatC],[CatD])
) piv;
DROP TABLE #Product
Result of Query
Product CatA CatB CatC CatD
Item A 10 5 NULL NULL
Item B 3 5 7 10
Result trying to achieve is
Product Cat1 Stock1 Cat2 Stock2 Cat3 Stock3 Cat4 Stock4
Item A CatA 10 CatB 5 CatC 0 CatD 0
Item B CatA 3 CatB 5 CatC 7 CatD 10
Thanks for the help
You need to create all combinations of Product and Category first. Then do a LEFT JOIN on #Product to get the Stock. Finally, use the result to pivot the data.
Since I'm not familiar with the PIVOT command, I used another technique called Dynamic Crosstab
DECLARE #sql NVARCHAR(MAX) = N'';
SELECT #sql =
'SELECT
Product' + CHAR(10);
SELECT #sql = #sql +
STUFF((
SELECT
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Category END) AS ' + QUOTENAME('Cat' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10) +
' ,MAX(CASE WHEN RN = ' + CONVERT(VARCHAR(3), t.RN) + ' THEN Stock END) AS ' + QUOTENAME('Stock' + CONVERT(VARCHAR(3), t.RN)) + CHAR(10)
FROM (
SELECT DISTINCT
RN = ROW_NUMBER() OVER(PARTITION BY Product ORDER BY(SELECT NULL))
FROM #Product
) t
FOR XML PATH('')
), 1, 1, ' ');
SELECT #sql = #sql +
'FROM(
SELECT
p1.Product,
p1.Category,
Stock = ISNULL(p2.Stock, 0),
RN = ROW_NUMBER() OVER(PARTITION BY p1.Product ORDER BY p1.Category)
FROM (
SELECT
t1.Product, t2.Category
FROM (
SELECT DISTINCT Product FROM #Product
) t1
CROSS JOIN (
SELECT DISTINCT Category FROM #Product
) t2
) p1
LEFT JOIN #Product p2
ON p1.Product = p2.Product
AND p1.Category = p2.Category
)t
GROUP BY Product;';
PRINT #sql;
EXEC sp_executesql #sql;
ONLINE DEMO

SQL Server dynamic pivot with multiple columns

Here's the scenario I am in. I have my data in the following format.
My source data
IssuedOn Country Sales Transactions
------------------------------------------
29-Aug-16 India 40 8
29-Aug-16 Australia 15 3
29-Aug-16 Canada 15 3
30-Aug-16 India 50 10
30-Aug-16 Australia 25 5
30-Aug-16 Canada 10 2
31-Aug-16 India 100 25
31-Aug-16 Australia 30 10
31-Aug-16 Canada 55 12
This is the output I am looking for
Expected output
IssuedDate Australia Canada India TotalSales Transactionscount
---------------------------------------------------------------------
29-Aug-16 15 15 40 70 14
30-Aug-16 25 10 50 85 17
31-Aug-16 30 55 100 185 47
I have been able to pivot the data on country and get the "Total Sales" column. However, I am not able to get the "Total Transactions" column right.
Here's the code to generate the source data table. Would really help if someone can guide me.
Create Table tbl1
(
IssuedOn date,
Country varchar(100),
Sales bigint,
Transactions bigint
)
Insert into tbl1(IssuedOn, Country, Sales, Transactions)
Values ('2016-08-29', 'India', 40, 8),
('2016-08-29', 'Australia', 15, 3),
('2016-08-29', 'Canada', 15, 3),
('2016-08-30', 'India', 50, 10),
('2016-08-30', 'Australia', 25, 5),
('2016-08-30', 'Canada', 10, 2),
('2016-08-31', 'India', 100, 25),
('2016-08-31', 'Australia', 30, 10),
('2016-08-31', 'Canada', 55, 12)
select *
from tbl1
A more verbose dynamic SQL query, without the use of a stored procedure is as follows:
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #pivotSales AS NVARCHAR(MAX);
DECLARE #sql AS NVARCHAR(MAX);
SELECT #cols = ISNULL(#cols + ', ', '') + QUOTENAME(Country)
FROM (SELECT DISTINCT Country FROM tbl1) AS Countries
SET #pivotSales = N'SELECT IssuedOn, ' + #cols +'
FROM (SELECT IssuedOn, Country, Sales FROM tbl1) AS sales
PIVOT(SUM(Sales) FOR Country IN (' + #cols + ')) AS pvt';
SET #sql = ';WITH CTE_SalesPivot AS (
'+#pivotSales+'
),
CTE_SalesTotal AS (
SELECT IssuedOn, SUM(Sales) AS [Grand Total]
FROM tbl1
GROUP BY IssuedOn
),
CTE_Transactions AS (
SELECT IssuedOn, SUM(Transactions) AS [Transaction Count]
FROM tbl1
GROUP BY IssuedOn
)
SELECT CTE_SalesPivot.IssuedOn, ' + #cols + ', CTE_SalesTotal.[Grand Total], CTE_Transactions.[Transaction Count]
FROM
CTE_SalesPivot
INNER JOIN CTE_SalesTotal ON CTE_SalesPivot.IssuedOn = CTE_SalesTotal.IssuedOn
INNER JOIN CTE_Transactions ON CTE_SalesPivot.IssuedOn = CTE_Transactions.IssuedOn';
EXEC sp_executesql #sql;
The following is the stored procedure used for the bulk of my dynamic pivots
Exec [prc-Pivot] 'tbl1','Country','sum(Sales)[]','IssuedOn','sum(Transactions)[Transactions],sum(Sales)[TotalSales]'
IssuedOn Transactions TotalSales Australia Canada India
2016-08-29 14 70 15 15 40
2016-08-30 17 85 25 10 50
2016-08-31 47 185 30 55 100
The stored procedure
ALTER PROCEDURE [dbo].[prc-Pivot] (
#Source varchar(1000), -- Any Table or Select Statement
#PvotCol varchar(250), -- Field name or expression ie. Month(Date)
#Summaries varchar(250), -- aggfunction(aggValue)[optionalTitle]
#GroupBy varchar(250), -- Optional additional Group By
#OtherCols varchar(500) ) -- Optional Group By or aggregates
AS
--Exec [prc-Pivot] 'Select Year=Year(TR_Date),* From [Chinrus-Series].[dbo].[DS_Treasury_Rates]','''Q''+DateName(QQ,TR_Date)','avg(TR_Y10)[-Avg]','Year','count(*)[Records],min(TR_Y10)[Min],max(TR_Y10)[Max],Avg(TR_Y10)[Avg]'
--Exec [prc-Pivot] '#Temp','Attribute','max(Description)[]','ID','count(*)[Records]'
Set NoCount On
Declare #Vals varchar(max),#SQL varchar(max);
Set #Vals = ''
Set #OtherCols= IsNull(', ' + #OtherCols,'')
Set #Source = case when #Source Like 'Select%' then #Source else 'Select * From '+#Source end
Create Table #TempPvot (Pvot varchar(100))
Insert Into #TempPvot
Exec ('Select Distinct Convert(varchar(100),' + #PvotCol + ') as Pvot FROM (' + #Source + ') A')
--Select #Vals = #Vals + ', isnull(' + Replace(Replace(#Summaries,'(','(CASE WHEN ' + #PvotCol + '=''' + Pvot + ''' THEN '),')[', ' END),NULL) As [' + Pvot ) From #TempPvot Order by Pvot
Select #Vals = #Vals + ', isnull(' + Replace(Replace(#Summaries,'(','(CASE WHEN ' + #PvotCol + '=''' + Pvot + ''' THEN '),')[', ' END),0) As [' + Pvot ) From #TempPvot Order by Pvot
Drop Table #TempPvot
Set #SQL = Replace('Select ' + Isnull(#GroupBy,'') + #OtherCols + #Vals + ' From (' + #Source + ') PvtFinal ' + case when Isnull(#GroupBy,'')<>'' then 'Group By ' + #GroupBy + ' Order by ' + #GroupBy else '' end,'Select , ','Select ')
--Print #SQL
Exec (#SQL)
here's a simple way to do it using aggregate case expressions.
DECLARE #cols NVARCHAR(MAX),
#sql NVARCHAR(MAX)
SELECT #cols = STUFF((
SELECT ',' + 'SUM(CASE WHEN Country = ''' + Country + ''' THEN Sales END) AS ' + QUOTENAME(Country)
FROM (SELECT DISTINCT Country FROM tbl1) t
ORDER BY Country
FOR XML PATH('')
),1, 1, '')
SET #sql = N'
SELECT IssuedOn, ' + #cols + ',
SUM(Sales) AS TotalSales,
SUM(Transactions) AS TransactionCount
FROM tbl1
GROUP BY IssuedOn
'
EXEC(#sql)
this will generate a query that should look like this.
SELECT IssuedOn,
SUM(CASE WHEN Country = 'Australia' THEN Sales END) AS [Australia],
SUM(CASE WHEN Country = 'Canada' THEN Sales END) AS [Canada],
SUM(CASE WHEN Country = 'India' THEN Sales END) AS [India],
SUM(Sales) AS TotalSales,
SUM(Transactions) AS TransactionCount
FROM tbl1
GROUP BY IssuedOn

SQL - How to insert multiple records as one record without pivot?

i want to create a query from multiple records as one record , but i don't want to use Pivot, is there any solutions?
here's the table :
ID Element_Name Value
1 Parmitha 100
2 Anggun 200
3 Chandra 300
4 BagusofTerror 400
and i want the result is like this :
paramitha , anggun, chandra , bagusofterror
100 , 200, 300, 400
You can use for xml path ('') to transpose the values of a column.
For example, you could write
select Element_Name + ', '
from TheTable
for xml path ('');
To get Parmitha, Anggun, Chandra, BagusofTerror,
Here's a live demo: http://www.sqlfiddle.com/#!3/71f88/24
You can also use COALESCE to pivot a results set of columns into a varchar variable:
CREATE TABLE #Pivot
(ID int, Element_Name varchar(50), Value int)
INSERT #Pivot values (1,'Parmitha',100)
INSERT #Pivot values (2,'Anggun',200)
INSERT #Pivot values (3,'Chandra',300)
INSERT #Pivot values (4,'BagusofTerror',400)
DECLARE #titles VARCHAR(1000)
DECLARE #values VARCHAR(1000)
SET #titles = ''
SET #values = ''
SELECT #titles = #titles + COALESCE(Element_Name + ',' , '')
FROM #Pivot ORDER BY ID
SELECT #values = #values + COALESCE(convert(varchar, Value) + ',' , '')
FROM #Pivot ORDER BY ID
SELECT #titles
UNION ALL
SELECT #values
Gives:
Parmitha,Anggun,Chandra,BagusofTerror,
100,200,300,400,
Try this :-
Select
MAX(CASE WHEN colID = 1 THEN value ELSE NULL END) AS [Parmitha],
MAX(CASE WHEN colID = 2 THEN value ELSE NULL END) AS [Anggun],
MAX(CASE WHEN colID = 3 THEN value ELSE NULL END) AS [Chandra],
MAX(CASE WHEN colID = 4 THEN value ELSE NULL END) AS [BagusofTerror]
FROM
(
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS colID,
ID,
Element_Name,
value
FROM Sample
) AS d
SQL DEMO
Taking Wolf's answer into consideration ,using dynamic query and xml path
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ','
+ convert(varchar(max), Element_Name, 120)
from Sample
FOR XML PATH(''), TYPE
).value('.', 'varchar(MAX)')
,1,1,'')
set #query = 'SELECT' + #cols + ' from
(
select value, Element_Name
from Sample
) x
pivot
(
max(value)
for Element_Name in (' + #cols + ')
) p '
execute(#query);
Demo
By the way y don't u use PIVOT .Using PIVOT the same result can be achieved
Select [Parmitha],[Anggun],[Chandra],[BagusofTerror]
FROM
(
Select value,element_name from Sample
)src
pivot
(
max(value)
for Element_Name in ([Parmitha],[Anggun],[Chandra],[BagusofTerror])
)pvt

Resources