DECLARE #FirstDayOfWeek DATETIME
SELECT #FirstDayOfWeek =
COALESCE(
cast(#FirstDayOfWeek AS VARCHAR(MAX)) + ',[' + cast(#FirstDayOfWeek AS VARCHAR(MAX)) + ']',
'[' + cast(#FirstDayOfWeek AS VARCHAR(MAX))+ ']'
)
FROM [Calendar] c
LEFT JOIN Stores s ON c.FirstDayOfMonth = s.Validfrom
left join POSProductDivPeriod pos ON c.Period = pos.Period
DECLARE #PivotTableSQL NVARCHAR(MAX)
SET #PivotTableSQL = N'
SELECT *
FROM (
SELECT
YEAR(FirstDayOfWeek) [Year],
#FirstDayOfWeek,
pos.quantity
FROM [Calendar] c
LEFT JOIN Stores s ON c.FirstDayOfMonth = s.Validfrom
left join POSProductDivPeriod pos ON c.Period = pos.Period
) AS PivotData
PIVOT (
SUM(pos.quantity)
FOR #FirstDayOfWeek IN (
' +CAST(#FirstDayOfWeek AS VARCHAR(MAX)) + '
)
) AS PivotTable
'
EXECUTE(#PivotTableSQL)
when i run all of this i get command complete
when i run execute i get must declare scarlar
im trying to run my code for my pivot table and for it to execute right after
any ideas ?
May this article will help you,
http://www.codeproject.com/Articles/201320/Dynamic-Pivoting-with-Cubes-and-eventhandlers-in-S
Related
I'm trying to replace NULL values with 0 in the following query, however without luck. I know I need to create another column list for the SELECT statement, but I've been unsuccessful so far.
How do I do this properly?
My query:
DECLARE #SQL AS NVARCHAR(MAX);
DECLARE #COLS AS NVARCHAR(MAX);
SELECT #COLS = ISNULL(#COLS + ',', '') + QUOTENAME(ItemCategoryName)
FROM
(
SELECT DISTINCT
ItemCategoryName
FROM sgdw.fact.RetailSales RS
JOIN SGDW.dim.Item I ON RS.ItemID = I.ItemID
WHERE RS.CalendarID >= '20190101'
AND storeid = '92'
AND DATALENGTH(ItemCategoryName) != 0
) AS Properties;
SET #SQL = N'SELECT *
FROM
(
SELECT RetailSalesAmountIncludingVATDKK,
ItemCategoryName,
ReceiptCode
FROM
(
SELECT *
FROM sgdw.fact.RetailSales
WHERE storeid = ''92''
UNION ALL
SELECT *
FROM sgdw.fact.RetailSales_hist
WHERE CalendarID >= ''20190101''
AND storeid = ''92''
) RS
JOIN SGDW.dim.Item I ON RS.ItemID = I.ItemID
JOIN SGDW.dim.Store S ON S.StoreID = RS.StoreID
) SourceTable
PIVOT (Sum(RetailSalesAmountIncludingVATDKK) FOR [ItemCategoryName] IN (' + #COLS + ')) as PivotTable';
EXEC sp_executesql
#SQL;
If you use SQL Server (starting with 2008), Azure SQL Database, Azure SQL Data Warehouse, Parallel Data Warehousen you can bye COALESCE method
like
SELECT #COLS_SUM = #COLS_SUM + 'COALESCE(' + QUOTENAME(finmonth) + ',0)+'
FROM (SELECT DISTINCT finmonth FROM YOUR_TABLE ) AS tmp
SELECT #COLS_SUM = ','+ SUBSTRING(#COLS_SUM, 0, LEN(#COLS_SUM)) +' AS TOTAL'
for more info check https://www.codeproject.com/Questions/1391827/Dealing-with-nulls-dynamic-columns-in-pivot
Append This
SELECT #COLS = 'ISNULL('+REPLACE(#COLS,',',',0 ) , ISNULL(') + ',0 )'
After this block
SELECT #COLS = ISNULL(#COLS + ',', '') + QUOTENAME(ItemCategoryName)
FROM
(
SELECT DISTINCT
ItemCategoryName
FROM sgdw.fact.RetailSales RS
JOIN SGDW.dim.Item I ON RS.ItemID = I.ItemID
WHERE RS.CalendarID >= '20190101'
AND storeid = '92'
AND DATALENGTH(ItemCategoryName) != 0
) AS Properties;
I have the following schema and sample data.
create table MyTable
(
Id int,
Year int,
Channel varchar(10),
Payments int
)
insert into MyTable values
(1,2012,'HV',100),
(1,2014,'HV',56),
(2,2012,'NL',17000)
(2,2012,'HV',495),
(3,2013,'HV',565)
Now I want to create and insert dynamic pivot data in a temporary table. I am able to create the pivot data as the demo here.
But I want to store this data into a temporary table. What I have tried is as below.
Declare #SQL varchar(max) = '
if object_id(''tempdb..##TempTable'') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TempTable
Select *
From (
Select A.Id
,B.*
From [dbo].[MyTable] A
Cross Apply ( values ( Id, Channel + CONVERT(Varchar(4), Year)
)) B (Item,Value)
) S
Pivot (sum([Payments]) For Channel + CONVERT(Varchar(4), Year) in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'') + ') ) p'
select #SQL
Exec(#SQL);
SELECT * FROM ##TempTable
It is giving me the following error.
Msg 102, Level 15, State 1, Line 18 Incorrect syntax near '+'.
When printing the dynamic query it is giving the following result.
if object_id('tempdb..##TempTable') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, [HV2012] Varchar(20) null,[HV2013] Varchar(20) null,[HV2014] Varchar(20) null,[NL2012] Varchar(20) null)
INSERT INTO ##TempTable
Select * From ( Select A.Id ,B.* From [dbo].[MyTable] A
Cross Apply ( values ( Id, Channel + CONVERT(Varchar(4), Year) )) B (Item,Value) ) S
Pivot (sum([Payments]) For Channel + CONVERT(Varchar(4), Year) in ([HV2012],[HV2013],[HV2014],[NL2012]) ) p
If you are using apply then why you need further same logic in PIVOT (i.e. Channel + CONVERT(Varchar(4), Year)) which is already available in apply.
So, i would use Value instead in PIVOT :
. . .
Pivot (sum([Payments]) For [Value] in ([HV2012],[HV2013],[HV2014],[NL2012]) ) p,
So, your updated Dynamic SQL would be :
Declare #SQL varchar(max) = '
if object_id(''tempdb..##TempTable'') is not null
begin
drop table ##TempTable
end
create table ##TempTable([Id] int null, ' +
Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year)) + ' Varchar(20) null'
From [dbo].MyTable
Order By 1
For XML Path('')),1,1,'')+ ')
INSERT INTO ##TempTable
Select *
From (
Select A.ID, A.Payments
,B.*
From [dbo].MyTable a
Cross Apply ( values ( Channel + CONVERT(Varchar(4), Year)
)) B ([Value])
) S
Pivot (sum([Payments]) For [Value] in
(' + Stuff((Select Distinct ','+QuoteName(Channel + CONVERT(Varchar(4), Year))
From #tm
Order By 1
For XML Path('')),1,1,'') + ') ) p'
print #sql
Exec(#SQL)
SELECT * FROM ##TempTable
I have made no of changes as there are many correction needs to be done prior to execution.
i have data in below format. this data is coming through SQL Query.
i want to show it in below format either by query or by rdlc report.
You need to use dynamic SQL to make it.
From your expected result you can try to follow thoes step to make it.
use row_number function make row number by Name, because we need to join base on that row_number.
get the use MAX and MIN to make row number calendar table. from 1 to max(rn). the table can let use outer join
declare a var #tables to make the OUTER JOIN execute SQL (each LEFT JOIN maen a group of Crew#).
declare a var #col to make column, which you want to select (Employee) from each table.
then use execute dynamic execute it.
look like this.
create table T
(
Name varchar(50),
Employee VARCHAR(50)
)
insert into T values ('Crew#1','TR123');
insert into T values ('Crew#1','311');
insert into T values ('Crew#2','DDD');
insert into T values ('Crew#2','12121');
insert into T values ('Crew#1','SDDAS');
insert into T values ('Crew#3','31114312');
insert into T values ('Crew#3','DD14124D');
insert into T values ('Crew#3','1214124121');
insert into T values ('Crew#3','SDD412AS');
DECLARE #tables AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#col AS NVARCHAR(MAX);
SET #tables = STUFF((SELECT distinct ' LEFT JOIN ' + ' (SELECT * FROM CTE WHERE Name = '''+Name+''') '+QUOTENAME(Name)+' on t1.smallRN = '+QUOTENAME(Name)+'.rn'
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = STUFF((SELECT distinct ', ' + QUOTENAME(Name)+'.Employee as '''+ QUOTENAME(Name) +''''
FROM T
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SET #col = substring(#col,1, len(#col))
set #query = '
WITH CTE AS (
SELECT *,ROW_NUMBER() OVER(PARTITION BY Name ORDER BY Name) rn
FROM T
),CTE1 AS(
SELECT MIN(rn) smallRN,MAX(rn) bigRN
FROM CTE
UNION ALL
SELECT smallRN+1,bigRN
FROM CTE1
WHERE smallRN < bigRN
)
SELECT '+#col+'
FROM CTE1 t1 ' + #tables
execute(#query)
sqlfiddle
Creatin tbale
First we will create a temp table where we will stock the data that you have and your table
create table #table1
(
[Crew Name] varchar(500) ,
Employee varchar(500)
)
INsert into #table1
values (....)
select * from #table1
Dynamic selection
then we will create a dynamic query to get the columns that we have, that way we can add as much crews as we want,
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
this way we will get only the first row for every column
so we have to find a way to aggregate and get the other columns as well just to demonstrate i will union the Mmin also this is where i stoped my testes but you can do more then this with some testes
now the union :
declare #DynamicPivotQuery as nvarchar(max)
declare #ColumnName as nvarchar(max)
select #ColumnName = ISNULL(#ColumnName +',','') + QUOTENAME([Crew Name])
from (select distinct [Crew Name] from #table1) as Country
set #DynamicPivotQuery = N'select ' +#ColumnName + '
from #table1
Pivot ( MAX(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
union
select ' +#ColumnName + '
from #table1
Pivot ( MIN(Employee)
FOR [Crew Name] in (' +#ColumnName+')) as Pivoted
'
exec (#DynamicPivotQuery)
here is the result :
if you follow this way i'm sure that you will find a way to union all the result
You can add this result into a temp table
then add a column which will be a reference into this temp table
then use pivot function
To know more about pivot Visit :
https://msdn.microsoft.com/en-us/azure/data-lake-analytics/u-sql/pivot-and-unpivot-u-sql
you can use also SSIS to a very handy tool and easy to use
Using dynamic PIVOT if you dont have a set Crew columns.
DECLARE #ColumnString VARCHAR(256)
DECLARE #ColumnHeadrer VARCHAR(256)
DECLARE #sql varchar(1000)
CREATE TABLE #ColumnValue
(
Value VARCHAR(500),
ColumnHeader VARCHAR(256)
)
INSERT INTO #ColumnValue (Value, ColumnHeader)
SELECT DISTINCT '[' + CrewName + ']',
'ISNULL(' + CrewName + ','''') AS ' + CrewName
FROM CrewTable
SELECT #ColumnString = COALESCE(#ColumnString + ',', '') + Value,
#ColumnHeadrer = COALESCE(#ColumnHeadrer + ',', '') + ColumnHeader
FROM #ColumnValue
SET #sql =
'
SELECT ' + #ColumnHeadrer + '
FROM
(
SELECT Employee,
CrewName,
ROW_NUMBER() OVER(PARTITION BY CrewName ORDER BY CrewName) AS rnk
FROM CrewTable
) AS P
PIVOT
(
MAX(Employee) FOR [CrewName] IN ('+#ColumnString+')
) AS pv
'
EXEC (#sql)
I have a question about the parametrization of a SQL query I created. The original query looks like this:
DECLARE #portfolios AS NVARCHAR(MAX)
DECLARE #Abfrage AS NVARCHAR(MAX)
SET #portfolios = STUFF((SELECT '[' + PortfolioName + '], ' FROM tblPortfolio ORDER BY PortfolioName FOR XML PATH('')),1,5,NULL)
SELECT #portfolios = LEFT(#portfolios,(LEN(#portfolios)-1))
SET #Abfrage ='
SELECT Description, ' + #portfolios + '
FROM
( SELECT tblReturnType.Description, tblPortfolio.PortfolioName, tblReturnAbs.Value
FROM
tblReturnType INNER JOIN ((tblReturnAbs INNER JOIN tblPortfolio ON tblReturnAbs.PortfolioNo = tblPortfolio.PortfolioNo) INNER JOIN tblInstrument ON tblReturnAbs.InstrumentNo =tblInstrument.InstrumentNo) ON (tblReturnType.ReturnType = tblReturnAbs.ReturnType)
WHERE (tblReturnAbs.Date BETWEEN ''01/01/17'' AND Dateadd("d",-1,''01/31/17'')) AND tblInstrument.Currency = ''EUR''
) AS x
PIVOT
(
sum(x.Value)
For x.PortfolioName in (' + #portfolios + ')
) AS piv
ORDER BY Description
'
Execute (#Abfrage)
It creates an output where a variable number of portfolios is displayed as columns, with different parts of portfolio earnings displayed under each portfolio name. Now, i would like to use parameters to be able to dynamically change the "WHERE" clause. At the same time, it should be possible to access the query from a frontend (which is yet to be decided). To achieve this, i tried to transform the query in a stored procedure like this:
ALTER PROCEDURE [dbo].[Return_Attribution]
#Startdate datetime,
#EndDate datetime,
#Currency nvarchar(10)
AS
BEGIN
DECLARE #portfolios AS NVARCHAR(MAX)
DECLARE #Abfrage AS NVARCHAR(MAX)
SET #portfolios = STUFF((SELECT '[' + PortfolioName + '], ' FROM tblPortfolio ORDER BY PortfolioName FOR XML PATH('')),1,5,NULL)
SELECT #portfolios = LEFT(#portfolios,(LEN(#portfolios)-1))
SET #Abfrage ='SELECT Description, ' + #portfolios + '
FROM
(SELECT tblReturnType.Description, tblPortfolio.PortfolioName, tblReturnAbs.Value
FROM tblReturnType
INNER JOIN ((tblReturnAbs
INNER JOIN tblPortfolio ON tblReturnAbs.PortfolioNo = tblPortfolio.PortfolioNo)
INNER JOIN tblInstrument ON tblReturnAbs.InstrumentNo =tblInstrument.InstrumentNo) ON (tblReturnType.ReturnType = tblReturnAbs.ReturnType)
WHERE (tblReturnAbs.Date >= '+ #Startdate +' AND tblReturnAbs.Date <= Dateadd("d",-1,'+ #EndDate +')) AND tblInstrument.Currency = '+ #Currency +'
) AS x
PIVOT
(
sum(x.Value)
For x.PortfolioName in (' + #portfolios + ')
) AS piv
ORDER BY Description
'
Execute (#Abfrage)
END
Now, if I try to execute this procedure and enter parameters, I get the following error:
Msg 8152, Level 16, State 10, Procedure Return_Attribution, Line 16
String or binary data would be truncated.
I did a bit of research and I found out that this error normally occurs when a string is too long to fit into a data field. As it only occurs when I used the parametrized procedure, I suppose I made a mistake in either defining or using the parameters. Any help would be appreciated.
This is my code:
declare #sql as varchar(max)
set #sql = 'insert into #TempReport select [Country],' + #cols + '
from
(
select
C.Country_Name AS [Country],
D.GSL_Name AS [GSL],
SUM(A.Allocation) AS Total
from Work_Information A
inner join Sales B
on A.Sales_ID = B.Sales_Id
inner join Countries C
on A.Country_ID = C.Country_ID
inner join tbl_GSL D
on A.GSL_ID = D.GSL_ID AND A.Sales_ID = D.Sales_Id
where A.Sales_Id = 1
group by A.Country_ID,C.Country_Name, A.Sales_ID, A.GSL_ID,D.GSL_Name
) P Pivot (sum(Total) for [GSL] in (' + #Cols + ')) as Pvt'
exec(#sql)
declare #SumCols as varchar(max)
select #SumCols = stuff(
(select ', Sum(' + quotename(GSLName) + ')' + REPLACE(GSLName,' ','') from
(
select TOP 200 GSL_Name as GSLName
from tbl_GSL GSL
where Sales_Id = 1
ORDER BY GSL_Name
) GlobalSales
ORDER BY GSLName FOR XML PATH('')
),1,2,'')
declare #sql3 as varchar(1000)
set #sql3 = 'select Country,' + #SumCols + ' from #TempReport group by Country WITH ROLLUP'
exec(#sql3)
I have posted only the relevant part of the code because the stored procedure is very long.
The code is working fine. I am using WITH ROLLUP clause to add Grand Total row and columns in the last. The last line of the code does adds a row at the last but I also want to add last column as Grand Total. Also, the last row added by ROLLUP should have first column value as Grand Total.