How to show Grand Total column using With RollUp - sql-server

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.

Related

Using pivot and then counting the values in each pivot column

I have a table that looks like this:
Agent_id
break_id
time
1
1
15
1
2
12
1
2
12
I used pivot to get this structure:
Agent_id
1
2
1
15
24
The problem is that I need to get the count for the pivoted columns, in the example I need to have a structure like this:
Agent_id
1
2
count1
count2
1
15
24
1
2
And I'm not sure on how to do it ... this is the query so far.
DECLARE #COLUMNS VARCHAR(MAX)
DECLARE #QUERY nVARCHAR(MAX)
SELECT #COLUMNS = COALESCE(#COLUMNS + ', ','') + QUOTENAME([break_id])
FROM
(SELECT DISTINCT [break_id] FROM test) AS B
ORDER BY B.[break_id]
SET #QUERY = '
SELECT agent_id,
'+#COLUMNS+'
FROM (
SELECT TOP (1000)
agent_id,break_id,time_inbreak
FROM test
) as pivotData
PIVOT (
SUM(time_inbreak)
FOR break_id IN ('+#COLUMNS+')
) as pivotResult
'
EXEC sp_executesql #QUERY
Any help is greatly appreciated
Unfortunately, PIVOT can only pivot a single column. But we can do multiple columns using conditional aggregation SUM(CASE WHEN... and COUNT(CASE WHEN...:
DECLARE #COLUMNS VARCHAR(MAX)
DECLARE #QUERY nVARCHAR(MAX)
SELECT #COLUMNS = COALESCE(#COLUMNS + ', ','') +
'Sum' + QUOTENAME([break_id]) +
' = SUM(CASE WHEN break_id = ' + break_id + ' THEN time_inbreak END), Count' +
QUOTENAME([break_id]) + ' = COUNT(CASE WHEN break_id = ' + break_id + ' THEN 1 END)'
FROM
(SELECT DISTINCT [break_id] FROM test) AS B
ORDER BY B.[break_id]
OPTION (MAXDOP 1);
SET #QUERY = '
SELECT agent_id,
'+#COLUMNS+'
FROM (
SELECT TOP (1000)
agent_id,break_id,time_inbreak
FROM test
) as pivotData
GROUP BY agent_id;
';
PRINT #QUERY
EXEC sp_executesql #QUERY
I must say, I'm not sure how safe it is to aggregate the columns like that, especially in the face of parallelism. Preferably use STRING_AGG or FOR XML PATH(''), TYPE. At the very least I have added OPTION (MAXDOP 1) to prevent parallelism

How to replace NULL values in T-SQL PIVOT with dynamic columns

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;

Get Dynamic Pivot Result into temp table SQL Server

I want to get dynamic pivot result into temp table by which I can send it back to C# code using select query.
DECLARE #partymasterid bigint = 2;
DECLARE #cols AS NVARCHAR(MAX);
DECLARE #query AS NVARCHAR(MAX);
SELECT
#cols = STUFF((SELECT DISTINCT '[' + CAST(dbo.InventoryProductMaster.Name AS nvarchar(max)) + '],'
FROM dbo.InventoryBiltyMaster
INNER JOIN dbo.InventoryPartyProductPriceMaster ON dbo.InventoryBiltyMaster.InventoryPartyProductPriceMasterID = dbo.InventoryPartyProductPriceMaster.ID
INNER JOIN dbo.InventoryProductMaster ON dbo.InventoryPartyProductPriceMaster.InventoryProductMasterID = dbo.InventoryProductMaster.ID
WHERE dbo.InventoryBiltyMaster.PartyMasterID = #partymasterid
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 0, '');
SELECT #query =
'
SELECT
*
FROM
(SELECT
Count(dbo.InventoryBiltyMaster.ID) AS BiltyCount,
--dbo.InventoryBiltyMaster.InventoryProductMasterID,
--dbo.InventoryBiltyMaster.VehicleMasterID,
dbo.InventoryProductMaster.Name,
dbo.VehicleMaster.VehicleNumber
FROM
dbo.InventoryBiltyMaster
INNER JOIN dbo.InventoryPartyProductPriceMaster ON dbo.InventoryBiltyMaster.InventoryPartyProductPriceMasterID = dbo.InventoryPartyProductPriceMaster.ID
INNER JOIN dbo.InventoryProductMaster ON dbo.InventoryPartyProductPriceMaster.InventoryProductMasterID = dbo.InventoryProductMaster.ID
INNER JOIN dbo.VehicleMaster ON dbo.InventoryBiltyMaster.VehicleMasterID = dbo.VehicleMaster.ID
WHERE
dbo.InventoryBiltyMaster.PartyMasterID = ' + CAST(#partymasterid as nvarchar(50)) + '
GROUP BY
dbo.InventoryBiltyMaster.InventoryProductMasterID,
dbo.InventoryProductMaster.Name,
dbo.InventoryBiltyMaster.VehicleMasterID,
dbo.VehicleMaster.VehicleNumber
)
AS S
PIVOT
(
MAX(BiltyCount)
FOR [Name] IN (' + LEFT(#cols, LEN(#cols)-1) + ')
)AS pvt';
EXEC SP_EXECUTESQL #query
Here may be result have 3 column or 5 columns or 10-15 columns. it depends on the result of query. and this result i want on temp table for use more this data.
I want to use it in a stored procedure to send back result into ASP.NET MVC 5 with Entity Framework
You can't store inside a # (temp table) without defining it in the parent scope when using sp_executesql. In your case you have a dynamic pivot and you don't know what and how many columns are going to be there.
sp_executesql runs in a different session (sp_executesql creates its own session) and temp tables are session specific.
For your scenario you can use ## (global temp table). You can change your query like following.
SELECT #query =
'
SELECT
* into ##temp
FROM
(SELECT
Count(dbo.InventoryBiltyMaster.ID) AS BiltyCount,
--dbo.InventoryBiltyMaster.InventoryProductMasterID,
--dbo.InventoryBiltyMaster.VehicleMasterID,
dbo.InventoryProductMaster.Name,
dbo.VehicleMaster.VehicleNumber
FROM
dbo.InventoryBiltyMaster
INNER JOIN dbo.InventoryPartyProductPriceMaster ON dbo.InventoryBiltyMaster.InventoryPartyProductPriceMasterID = dbo.InventoryPartyProductPriceMaster.ID
INNER JOIN dbo.InventoryProductMaster ON dbo.InventoryPartyProductPriceMaster.InventoryProductMasterID = dbo.InventoryProductMaster.ID
INNER JOIN dbo.VehicleMaster ON dbo.InventoryBiltyMaster.VehicleMasterID = dbo.VehicleMaster.ID
WHERE
dbo.InventoryBiltyMaster.PartyMasterID = ' + CAST(#partymasterid as nvarchar(50)) + '
GROUP BY
dbo.InventoryBiltyMaster.InventoryProductMasterID,
dbo.InventoryProductMaster.Name,
dbo.InventoryBiltyMaster.VehicleMasterID,
dbo.VehicleMaster.VehicleNumber
)
AS S
PIVOT
(
MAX(BiltyCount)
FOR [Name] IN (' + LEFT(#cols, LEN(#cols)-1) + ')
)AS pvt';
EXEC SP_EXECUTESQL #query
--now you can use ##temp
Note: use of global temp table can lead to unpredictable behavior if it gets updated from multiple sessions, you may think of giving a unique name for each session.

Error on parametrization of a query

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.

How to not include a certain column during query in SQL Server 2008

Thank you for the reply, but again im already using dynamic fields.
For example:
DECLARE #columns VARCHAR(8000)
SELECT #columns = COALESCE(#columns + ',[' + cast(QuestionName as varchar) + ']', '[' + cast(QuestionName as varchar)+ ']')
FROM Answer A
INNER JOIN Question Q ON A.QuestionID = Q.QuestionID
INNER JOIN Customer C ON A.CustomerID = C.CustomerID
GROUP BY Q.QuestionName
SET #columns = '[CustomerID],' + #columns
DECLARE #query VARCHAR(8000)
SET #query = 'Some PIVOT query without aggregation'
EXECUTE(#query)
But i want to arrange the fields in #columns..i want 1 field to be 1st:
#columns = [f1],[f2],[f3].
What i want is like this:
#columns = [f2],[f1],[f3] :
Because one of the fetch data..is constant in my report..
and should be place in the beginning or the first row to be displayed.

Resources