How do I flatten/pivot a sql result set? - sql-server

I have a SQL result set that looks like the following:
How can I get this result to display only ONE row for each ItemCode? Using a GROUP BY does not seem to work as it requires me to include columns that prevent the grouping I'm looking for.
The query I have written is pulling data from a table with a row for each warehouse and I am trying to format it in a way that I only have one row for each ItemCode. I think pivoting is the term what I'm trying to do..
Here is what my query looks like currently:
SELECT
ItemCode,
ISNULL((SELECT Quantity WHERE WhsCode = 10), 0) 'Whs10QTY',
ISNULL((SELECT Quantity WHERE WhsCode = 20), 0) 'Whs20QTY',
ISNULL((SELECT SalesAmt WHERE WhsCode = 10), 0) 'Whs10SalesAmt',
ISNULL((SELECT SalesAmt WHERE WhsCode = 20), 0) 'Whs20SalesAmt',
ISNULL((SELECT GrssProfit WHERE WhsCode = 10), 0) 'Whs10GrssProfit',
ISNULL((SELECT GrssProfit WHERE WhsCode = 20), 0) 'Whs20GrssProfit'
FROM
#Table t
Note: I may need help rewording and retitling this question as to make it more useful for the community. Thanks for any help guys!

I think you can simplify this as such:
Select ItemCode
,Whs10QTY = sum(case when WhsCode = 10 then Quantity else 0 end)
,Whs20QTY = sum(case when WhsCode = 20 then Quantity else 0 end)
,Whs10SalesAmt = sum(case when WhsCode = 10 then SalesAmt else 0 end)
,Whs20SalesAmt = sum(case when WhsCode = 20 then SalesAmt else 0 end)
,Whs10GrssProfit = sum(case when WhsCode = 10 then GrssProfit else 0 end)
,Whs20GrssProfit = sum(case when WhsCode = 20 then GrssProfit else 0 end)
From #Table t
Group By ItemCode

Related

How to identify why rows are duplicating

The below query selects all the rows from a master table (there are no duplicates in the table i have checked) and this query counts the number of business days and checks it against a certain number of days, if the count is greater than that certain number of days, it is late, else it is not late. For some reason when I run this query, even with the select DISTINCT, my rows are duplicating. I see a row for each tracking number showing one as Late and the other as Not Late but I don't see how they could possibly be showing both answers? Could anyone help me understand why my rows are being duplicated?
SELECT DISTINCT case UT.[Service] when '0PW' then 'UPS SurePost 1 lb or Greater' else UT.[Service] end as 'Service'
,US.[Region]
,UT.[Tracking_Number] as 'TrackingCounts'
,UT.Manifest_Date
,UT.Date_Delivered
,Ship_To_Postal_Code
,WarehouseLocation
,CASE
WHEN UT.[Service] = 'UPS Ground' AND WarehouseLocation = 'Wausau' then iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) )
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > UZ.TNTDAYS, 1, 0)
WHEN UT.[Service] in ('UPS SurePost 1 lb or Greater','UPS SurePost Less than 1 lb','0PW') AND WarehouseLocation = 'Wausau' then iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) )
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > (UZ.TNTDAYS + 1), 1, 0)
ELSE iif(((
DATEDIFF(dd, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END))
-(DATEDIFF(wk, UT.[Manifest_Date], CASE WHEN (UT.[Date_Delivered] = '1/1/2099') THEN GETDATE() WHEN (UT.[Date_Delivered] IS NULL) THEN GETDATE() ELSE UT.[DATE_DELIVERED] END) * 2)
-(CASE WHEN DATENAME(dw, UT.[Manifest_Date]) = 'Sunday' THEN 1 ELSE 0 END)
-(CASE WHEN DATENAME(dw, UT.[Date_Delivered]) = 'Saturday' THEN 1 ELSE 0 END)
-(Select Count(*) from [Reporting_Operations].[CORP\u694172].[tbl_HolidayDates] where [HolidayDate] between UT.[Manifest_Date] and UT.[Date_Delivered])) > USS.[Days], 1, 0)
End as LATE
FROM [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_QVM_Tracking] UT
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_States] US on US.[State] = UT.[Ship_To_State_Province]
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Ground_Zips] UZ on UZ.[DESTZIPCODE] = UT.[Ship_To_Postal_Code]
INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Services] USS on UT.[Service] = UT.[Service]
where cast(UT.Manifest_Date as date) between '1/20/2019' and '1/26/2019' AND WarehouseLocation = 'Wausau' and UT.Status = 'Delivered'
group by UT.[Service],US.[Region], USS.Days, UT.[Manifest_Date], UT.[Date_Delivered], TNTDAYS, Tracking_Number, Ship_To_Postal_Code, WarehouseLocation
So I found the issue is on INNER JOIN [Reporting_Operations].[CORP\u694172].[tbl_UPS_Automation_Services] USS on UT.[Service] = UT.[Service]
however I don't understand why when i join UT.SERVICE on USS.Service the uss.service field shows every possible service, and not the value that Ut.SERVICE has.
if UT.Service = UPS 2nd Day Air wouldn't the join on USS only give me UPS 2nd Day Air values?
The root cause is one of the joins returns more than 1 records
The way you need to find the the root cause of issue is:
1- Remove all columns from your select to become Select * from yourtable
2- comment all joins
3- uncomment joins and watch your data to see if the become duplicate
3.1- if the records are not duplicated that join is OK, do the same on next join
3.2- if records get duplicated, means join might not be right, usually some join conditions are missing
4- After fixing the join issue, remove * and bring back the fields
5- do final check

Convert vertical table to horizontal in SQL Server

I have a large table that has 8 row numbers with an associated loss and carrier. I am trying to convert into a horizontal structure.
CREATE TABLE #mytable
(
[ID] int NULL,
[RowNum] bigint NULL,
[Loss] float NULL,
[Carrier] nvarchar(255) NULL
)
INSERT INTO #mytable ([ID], [RowNum], [Loss], [Carrier])
VALUES (1,1, 0, 'test1'),
(1,2, NULL, 'test2'),
(1,3, 1.95, 'test3'),
(1,4, 51, 'test4'),
(1,5, 105.75, 'test5'),
(1,6, 0, 'test6'),
(1,7, 173, 'test7'),
(1,8, 256.35, 'test8'),
(2,1, 33158.3, 'test1'),
(2,2, 7925396, 'test2'),
(2,3, 0, 'test3'),
(2,4, NULL, 'test4'),
(2,5, 2461684, 'test5'),
(2,6, 159392, 'test6'),
(2,7, 14791, 'test7'),
(2,8, 14555, 'test8');
I am trying to get a horizontal table like the following (per id and a horizontal structure for Loss and Carrier):
I was trying case when end statements, but I wasn't achieving the desired results.
Can someone please help? I appreciate it.
This has been asked and answered hundreds of times. But it was easier to code a solution than point you to a duplicate. Excellent job posting table structure, sample data and desired output!!!
The easiest solution is using conditional aggregation like this.
select ID
, Loss1 = max(case when RowNum = 1 then Loss end)
, Loss2 = max(case when RowNum = 2 then Loss end)
, Loss3 = max(case when RowNum = 3 then Loss end)
, Loss4 = max(case when RowNum = 4 then Loss end)
, Loss5 = max(case when RowNum = 5 then Loss end)
, Loss6 = max(case when RowNum = 6 then Loss end)
, Loss7 = max(case when RowNum = 7 then Loss end)
, Loss8 = max(case when RowNum = 8 then Loss end)
, Carrier1 = max(case when RowNum = 1 then Carrier end)
, Carrier2 = max(case when RowNum = 2 then Carrier end)
, Carrier3 = max(case when RowNum = 3 then Carrier end)
, Carrier4 = max(case when RowNum = 4 then Carrier end)
, Carrier5 = max(case when RowNum = 5 then Carrier end)
, Carrier6 = max(case when RowNum = 6 then Carrier end)
, Carrier7 = max(case when RowNum = 7 then Carrier end)
, Carrier8 = max(case when RowNum = 8 then Carrier end)
from #mytable
group by ID

SQL procedure sum and sum inside select and insert to

I have a little problem. I have a insert into block with select and inside select I have sum. Thats works well. But In this select I need also do some operation on these sums. I don't know how.
Code:
insert into [dbo].[DiscountDailyStatsTemp]
SELECT
#DiscountId,
cast([dbo].[TelemetryData].[EventTime] as date) as 'Date',
sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountLike' then 1 else 0 end) as 'Likes',
sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountDislike' then 1 else 0 end) as 'Dis likes',
sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountShare' then 1 else 0 end) as 'Shares',
SUM(case when [dbo].[TelemetryData].[EventName]='DiscountView' then 1 else 0 end) as 'Views',
SUM(case when [dbo].[TelemetryData].[EventName]='DiscountClick' then 1 else 0 end) as 'Clicks',
Sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountCode' then 1 else 0 end) as 'Downloaded codes',
Sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountSave' then 1 else 0 end) as 'Saves',
sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountClickWWW' then 1 else 0 end) as 'Page redirections',
0 as 'Average CTR',
#UniqueUsers as 'Unique users',
#NewUsers as 'New users',
#ReturningUsers as 'Returning users',
Sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountCommentPositive' then 1 else 0 end) as 'Positive comments',
sum(case when [dbo].[TelemetryData].[EventName] = 'DiscountCommentNegative' then 1 else 0 end) as 'Negative comments'
from [dbo].[TelemetryData]
where [dbo].[TelemetryData].[DiscountId] = #DiscountId
and ([dbo].[TelemetryData].[EventName] = 'DiscountView' or [dbo].[TelemetryData].[EventName] = 'DiscountClick' or
[dbo].[TelemetryData].[EventName] = 'DiscountDislike' or [dbo].[TelemetryData].[EventName] = 'DiscountCode' or
[dbo].[TelemetryData].[EventName] = 'DiscountLike' or [dbo].[TelemetryData].[EventName] = 'DiscountShare' or
[dbo].[TelemetryData].[EventName] = 'DiscountClickWWW' or [dbo].[TelemetryData].[EventName] = 'DiscountSave' or
[dbo].[TelemetryData].[EventName] = 'DiscountCommentPositive' or [dbo].[TelemetryData].[EventName] = 'DiscountCommentNegative')
group by cast([dbo].[TelemetryData].[EventTime] as date)
order by cast([dbo].[TelemetryData].[EventTime] as date) asc
And look there is 0 as 'Average CTR' I need to change it for this:
Round(cast('Clicks' as float) / cast(case when 'Views' = 0 then 1 else 'Views') end as float) * 100, 2) as 'Average CTR',
But it not working. How I can do it?
You can't use the aliases in the same level they are created, and also this is a query with a group by clause, which means each column should be either in the group by or with an aggregation function around it.
You can wrap your query with another select :
SELECT [date],
[likes],
....
Round(cast([Clicks] as float) / cast(case when [Views] = 0 then 1 else [Views] end) as float) * 100, 2) as [Average CTR],
FROM(YOUR QUERY HERE)
Also, use square brackets for columns name.

When I SUM values of each month between 2 dates, I get the wrong value

I am really struggling with a query. I want the sum of each month between Aug 2014 and July 2015. If I specify the between dates in the where clause it sums all the months.
Here is my query:
DECLARE #CurrentYear int = DATEpart(year,getdate())
DECLARE #PreviousYear int = DATEpart(year,getdate()) -1
SELECT
SUM(CASE WHEN a.fin_period = concat(#PreviousYear,'08') THEN a.balance ELSE 0 END) AS BalanceAug ,
SUM(CASE WHEN a.fin_period = concat(#PreviousYear,'09') THEN a.balance ELSE 0 END) AS BalanceSep ,
SUM(CASE WHEN a.fin_period = concat(#PreviousYear,'10') THEN a.balance ELSE 0 END) AS BalanceOct ,
SUM(CASE WHEN a.fin_period = concat(#PreviousYear,'11') THEN a.balance ELSE 0 END) AS BalanceNov ,
SUM(CASE WHEN a.fin_period = concat(#PreviousYear,'12') THEN a.balance ELSE 0 END) AS BalanceDec ,
...etc.
FROM subaccount_history a with (nolock)
WHERE fin_period between concat(#PreviousYear,'08') and concat(#CurrentYear,'12')
The issue is with the between clause, i tried group by but that also doesn't work. It sums everything between the 2 dates specified.

ORA-00937: Not a single-group group function - Query error

Error: ORA-00937: Not a single-group group function
Query:
select count(*) todas,
sum(case when i.prioridade = 1 then 1 else 0 end) urgente,
sum(case when i.prioridade = 2 then 1 else 0 end) alta,
sum(case when i.prioridade = 3 then 1 else 0 end) normal,
sum(case when i.prioridade = 4 then 1 else 0 end) baixa,
(select count(*)
from GMITEMOS i
inner join GMCTLSLA c on c.os = i.cd_numero_os and c.item = i.item
where i.situacao in ('A', 'I', 'P')
and c.ordem = 99999
) naoAvaliados,
sum(case when i.situacao = 'P' then 1 else 0 end) pendentes,
sum(case when i.situacao = 'A' or i.situacao = 'I' then 1 else 0 end) iniciados
from GMITEMOS i
where i.situacao in ('A', 'I', 'P')
and exists (select 1
from GMCTLSLA c
where c.os = i.cd_numero_os
and c.item = i.item)
The error is ocurring here:
(select count(*)
from GMITEMOS i
inner join GMCTLSLA c on c.os = i.cd_numero_os and c.item = i.item
where i.situacao in ('A', 'I', 'P')
and c.ordem = 99999
) naoAvaliados
Can someone tell why is it happening?
You may have fixed it with max but that's not why it's happening and is a little bit hacky. Your problem is that your sub-query, which translates into a single column is not an aggregate query, min, max, sum etc and so needs to be included in a group by clause. You fixed this by wrapping it in max as the maximum of a single value will always be constant.
However, as your sub-query is, itself, an analytic query and will only ever return one row the obvious thing to do is to use a cartesian join to add it to your query. In the explicit join syntax this is known as the cross join.
select count(*) todas
, sum(case when i.prioridade = 1 then 1 else 0 end) urgente
, sum(case when i.prioridade = 2 then 1 else 0 end) alta
, sum(case when i.prioridade = 3 then 1 else 0 end) normal
, sum(case when i.prioridade = 4 then 1 else 0 end) baixa
, naoAvaliados
, sum(case when i.situacao = 'P' then 1 else 0 end) pendentes
, sum(case when i.situacao = 'A' or i.situacao = 'I' then 1 else 0 end) iniciados
from GMITEMOS i
cross join (select count(*) as naoAvaliados
from GMITEMOS j
inner join GMCTLSLA k
on k.os = j.cd_numero_os
and k.item = j.item
where j.situacao in ('A', 'I', 'P')
and k.ordem = 99999
)
where i.situacao in ('A', 'I', 'P')
and exists (select 1
from GMCTLSLA c
where c.os = i.cd_numero_os
and c.item = i.item
)
The cartesian join has a bad reputation as it multiples the number of rows on one side of the join by the number of rows on the other. It does, however, have it's uses, especially in this sort of case.
It's happening because the subquery itself is a scalar result, not a group function. As you have apparently found, you can fix it by substituting a group function that yields an equivalent result to your subquery.
In merge statement, if you are getting this error than simple use the group by and it will resolve the issue.
merge into table1 tb1
using
(select a.id,a.ac_no,sum(a.qy) as qyt,sum(a.amt) as sum_amt from
table2 a, table1 b
where a.id=b.id
and a.id = '1234'
and a.date = '08Oct2014'
and a.ac_no in (123, 234, 345)
and a.ac_no = b.ac_no
group by a.ac_no,a.id
)qry
on (qry.id=tb1.id and qry.ac_no=tb1.ac_no )
when matched then
update set qy=qry.qy,amt = qry.sum_amt;

Resources