Query is returning to rows instead of just one - sql

I have a a query to return the dimensions of a package in M2 (square metres) and UN (unity's). With the current query it is returning two different lines, because I am using a CASE WHEN. This is the query:
SELECT DISTINCT(C.Package) 'Package',
CASE S.Unity WHEN 'M2' THEN SUM(L.Qt*S.ConvEst) ELSE NULL END 'M2',
CASE S.Unity WHEN 'UN' THEN SUM(L.Qt) ELSE NULL END 'UN'
FROM
PackageTable AS C
INNER JOIN
PackageTableRows L ON L.Package = C.Package
INNER JOIN
Products S ON S.Product = L.Product
WHERE
C.Package = '587496'
GROUP BY
C.Package, S.Unity
This result:
But what I really want is the query to return is something like this:
With only one line. I know for that I am not using CASE WHEN correctly and that is why I need your help.

You have several problems here. Firstly, DISTINCT is not a function it's an operator. DISTINCT affects the entire dataset and causes only distinct rows to be returned. It's not DISTINCT ({Column Name}) it's SELECT DISTINCT {Columns}.
Next, you have both DISTINCT and GROUP BY; this is a flaw. A GROUP BY clause already causes your data to be returned in distinct groups, so a DISTINCT is both redundant and unneeded overhead. Get rid of the DISTINCT. If you are getting different results when you have a DISTINCT with a GROUP BY this is a strong indication that your GROUP BY clause is wrong and needs addressing (most likely you have too many columns in the clause).
Finally, when performing conditional aggregation the aggregate function should be around the entire CASE expression, not an expression in the THEN. Then also means that you then need to remove the column in your WHEN clause from the GROUP BY as I suspect the only reason you have it there is because you had to:
This results in:
SELECT C.Package AS Package,
SUM(CASE S.Unity WHEN 'M2' THEN L.Qt * S.ConvEst END) AS M2,
SUM(CASE S.Unity WHEN 'UN' THEN L.Qt END) AS UN
FROM dbo.PackageTable C
INNER JOIN dbo.PackageTableRows L ON L.Package = C.Package
INNER JOIN dbo.Products S ON S.Product = L.Product
WHERE C.Package = '587496'
GROUP BY C.Package;

It's mostly correct. You need to GROUP BY only on C.Package to bring it into a single line. For this it should return 0 for case else conditions and aggregation should be on the full case conditions rather than only on the measure.
So it will look like this.
SELECT C.Package 'Package',
SUM(CASE S.Unity WHEN 'M2' THEN (L.Qt*S.ConvEst) ELSE 0 END ) as 'M2',
SUM(CASE S.Unity WHEN 'UN' THEN SL.Qt ELSE 0 END) AS 'UN'
FROM PackageTable AS C
INNER JOIN PackageTableRows L ON L.Package=C.Package
INNER JOIN Products S ON S.Product=L.Product
WHERE C.Package='587496'
GROUP BY C.Package

Related

Attempting to use result of Case Expression in a join .. need to improve query

I have the following query which allows me to join the TransactionClass tables base on TransactionClassID from either the primary table (Transactions) or TransactionRules based on a condition as below:
SELECT
Description,
TC.Name,
(CASE
WHEN (TR.TransactionRuleId > 0)
THEN TR.TransactionRuleId
ELSE T.TransactionClassId
END) As ClassId
FROM Transactions AS T
LEFT JOIN TransactionRules TR ON T.Description LIKE TR.Pattern
LEFT JOIN TransactionClasses TC ON TC.TransactionClassId =
(CASE
WHEN (TR.TransactionRuleId > 0)
THEN TR.TransactionClassId
ELSE T.TransactionClassId
END)
The query is running on SQL Server,
In effect, it retrieves the correct TransactionClass entry depending on whether or not the join on TransactionRules was successful or not.
The above query works, but I am trying to simplify the query so that I do not have to repeat the CASE expression in two places.
I attempted to capture the result of the case expression in a variable and use that as follows:
SELECT
Description,
x
FROM Transactions AS T
LEFT JOIN TransactionRules TR
ON T.Description LIKE TR.Pattern
LEFT JOIN TransactionClasses TC
ON TC.TransactionClassId = x
WHERE x = (CASE
WHEN (TR.TransactionRuleId > 0)
THEN TR.TransactionRuleId
ELSE T.TransactionClassId
END)
But I get the error:
[S0001][207] Line 8: Invalid column name 'x'.
Where am I going wrong in my attempt to have only one CASE Expression?
CROSS APPLY is a tidy way to reuse a calculated value e.g.
SELECT
[Description]
, TC.[Name]
, Class.Id
FROM Transactions AS T
LEFT JOIN TransactionRules TR ON T.[Description] LIKE TR.Pattern
CROSS APPLY (
VALUES (
CASE
WHEN TR.TransactionRuleId > 0
THEN TR.TransactionRuleId
ELSE T.TransactionClassId
END
)
) AS Class (Id)
LEFT JOIN TransactionClasses TC ON TC.TransactionClassId = Class.Id;

Arithmetic overflow error converting varchar to data type numeric CASE statement

I am trying to write a query that returns an "Estimated Annual Value", and for this, I am using a Case statement. There are two inner joins involved in the query.
So, the query and gives me result when I am running this piece:
select Users.Id, Name, PhoneNumber, Email, Currency, count(*) as TotalOrders, sum(TotalCustomerAmount) as TotalOrderValue, avg(TotalCustomerAmount) as AverageOrderValue, TsCreate as RegistrationDate, max(TsOrderPlaced) as LastOrderDate, min(TsOrderPlaced) as FirstOrderDate,
CASE
When PromotionsEnabled = 0 then 'Y'
When PromotionsEnabled = 1 then 'n'
else 'undefined'
end as Promotions,
/*CASE
When ((DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced)) >= 6) AND (count(*) > 3)) then ((sum(TotalCustomerAmount)/(DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced))))*365)
Else '-'
end as EstimatedAnnualValue*/
from AspNetUsers with (nolock)
inner join Orders with (nolock) on Orders.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
and Orders.OrderState in (2,3,4,12)
inner join UserWhiteLabelConfigs with (nolock) on UserWhiteLabelConfigs.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
where AspNetUsers.Discriminator = 'ApplicationUser'
group by Users.Id, Name, Number, Currency, Email, TsCreate, PromotionsEnabled
But the problem comes when I am running this with the second CSAE statement, is it because I cannot use the aggregate function before GROUP BY? I am also thinking of using a Subquery
Looking fr some help!!
You need to use aggregation functions. For instance, if you want 'Y' only when all values are 0 or NULL:
(case when max(PromotionsEnabled) = 0 then 'Y'
when max(PromotionsEnabled) = 1 then 'N'
else 'undefined'
end) as Promotions,
I'm not sure if this is the logic you want (because that detail is not in the question). However, this shows that you can use aggregation functions in a case expression.

Receiving this error: The multi-part identifier "c.hrmort" could not be bound

All solutions point to the fact that if I've assigned aliases in my code, I should be using them instead of the table name itself. I have assigned alias and I AM trying to use the alias, however, I am still receiving this error.
Does this have to do with using an left join?
My code is as follows:
Select
x.MrtCategory
from
(select case
when c.hrmort='CMHC' then 'CMHC'
when c.hrmort='Genworth' then 'Genworth'
when c.hrmort=''
and a.purp in ('P16','P17')
and c.tenure in ('Freehold','Condo','Strata')
and a.secval<1000000
and a.amorty<=25
and a.class in ('Standard','Stf Benefit Rate','Stf Member Rate')
and a.totltov<80
then 'Conventional Insurable'
when c.hrmort IS NULL then 'Other'
else 'Conventional UnInsurable'
end as MrtCategory,
sum(a.amount) as 'Amount'
from
ODS_WB.dbo.lnap as a left join ODS_WB.dbo.cust as b on a.no_=b.no_ and a.surname=b.surname
left join ODS_WB.dbo.scur as c on b.rowno=c.rowno_custscur_cust and a.secval=c.secvalue and c.status='active'
where
year(a.appdate)=2020 and month(a.appdate)=6 and a.apptype='Mortgage' and a.sourcecode in ('FI',' ')) as x
group by
c.hrmort
Your group by is outside of the subquery, so c.hrmort doesn't exist.
Instead group by x.MrtCategory and sum the amount outside of the subquery:
Select x.MrtCategory,
sum(x.amount) as Amount
from (
select
case
when c.hrmort='CMHC' then 'CMHC'
when c.hrmort='Genworth' then 'Genworth'
when c.hrmort=''
and a.purp in ('P16','P17')
and c.tenure in ('Freehold','Condo','Strata')
and a.secval<1000000
and a.amorty<=25
and a.class in ('Standard','Stf Benefit Rate','Stf Member Rate')
and a.totltov<80
then 'Conventional Insurable'
when c.hrmort IS NULL then 'Other'
else 'Conventional UnInsurable'
end as MrtCategory,
-- sum(a.amount) as 'Amount'
a.amount
from ODS_WB.dbo.lnap as a
left join ODS_WB.dbo.cust as b on a.no_=b.no_ and a.surname=b.surname
left join ODS_WB.dbo.scur as c on b.rowno=c.rowno_custscur_cust and a.secval=c.secvalue and c.status='active'
where year(a.appdate)=2020
and month(a.appdate)=6
and a.apptype='Mortgage'
and a.sourcecode in ('FI',' ')
) as x
--group by c.hrmort -- c doesn't exist outside of the above subquery
group by x.MrtCategory

ORA-00934: group function is not allowed here when adding case when

I have a piece of code which runs fine. However, when i am introducing a "case when" statement in the select clause, I get the "group function is not allowed here" error and I cannot fix it (the issue relates to the last Group by function in my code)
Any idea why (don't be put off by the code, it is 3 joins together, apparently the issue is caused by the last Group By statement) ?
Thank you!
SELECT
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then (SUM(Trans_Table.MTTRANS01_VALUENCU)*-1)
else SUM(Trans_Table.MTTRANS01_VALUENCU) END) AS MTTRANS01_VALUENCU
FROM MTTRANS01 Trans_Table
INNER JOIN RUTRANTYPE01 Trans_Type
ON Trans_Type.RUTRANTYPE01_CODE = Trans_Table.RUTRANTYPE01_CODE
LEFT JOIN(
SELECT
MTAGRE01_NO
,CASE WHEN SRAGRESTAT01_CODE = 'COLL' THEN MTAGRE01_AGRESTATDATE END AS Date_Fr
from MTAGRE01
where CASE WHEN SRAGRESTAT01_CODE = 'COLL' THEN MTAGRE01_AGRESTATDATE END is not null
) F_Date
ON F_Date.MTAGRE01_NO = Trans_Table.MTAGRE01_NO
LEFT JOIN(
SELECT
Trans_Table.MTAGRE01_NO
FROM MTTRANS01 Trans_Table
INNER JOIN RUTRANTYPE01 Trans_Type ON Trans_Type.RUTRANTYPE01_CODE = Trans_Table.RUTRANTYPE01_CODE
GROUP BY
Trans_Table.MTAGRE01_NO, Trans_Type.RUTRANTYPE01_CODE, Trans_Type.RUTRANTYPE01_DESCRIPTION
) Cash
ON Cash.MTAGRE01_NO = Trans_Table.MTAGRE01_NO
where Trans_Type.SRPROCTYPE01_CODE in ('C','D')
and Trans_Table.MTTRANS01_VALUEDATE >= F_Date.Date_Fr
GROUP BY
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then (SUM(Trans_Table.MTTRANS01_VALUENCU)*-1)
else SUM(Trans_Table.MTTRANS01_VALUENCU) END);
I believe it's hung up on the sum inside the case statement. 2 routes to correct that I can see, likely alot more:
This is a little hacky, but it'll work and give results fast. Change your case:
SELECT
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then ((Trans_Table.MTTRANS01_VALUENCU)*-1)
else (Trans_Table.MTTRANS01_VALUENCU) END) AS MTTRANS01_VALUENCU
Remove the case from the group by.
Now call your entire query a sub query
Select MTAGRE01_NO, sum(MTTRANS01_VALUENCU)
(your entire query)a
You other option that takes a bit more work...in your initial from statement:
MTTRANS01 Trans_Table
Change that to a subquery that joins to the trans table and returns
case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then ((Trans_Table.MTTRANS01_VALUENCU)*-1)
else (Trans_Table.MTTRANS01_VALUENCU) END as MTAGRE01_NO
Then join to that subquery and do a simple sum in your main query.
Hopefully that all makes sense, ask questions if you need clarifications

DATEDIFF in Group by causing error

I am posting it a new question as previous question has changed a bit. I am using this query:
SELECT DATEDIFF(SECOND,servicestart,CheckinTime) abondendedTime FROM Location L INNER JOIN
Interaction I
ON L.Id = I.IdLocation
WHERE ServiceEnd = '00:00:00.000'
GROUP BY L.Id, L.Description,DATEDIFF(SECOND,servicestart,CheckinTime)
and it is returning 700 rows where as I don't need this part
DATEDIFF(SECOND,servicestart,CheckinTime) in GROUP BY but If I don't put it in GROUP BY, I get error:
Column 'Interaction.ServiceStart' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I want this result set
http://prntscr.com/f993xe
I need to do these calculations.
http://prntscr.com/f995dk
I have done this part
SELECT L.Id,
L.Description AS 'Location',
COUNT(L.Id) Interactions,
SUM(CASE WHEN I.ServiceEnd = '00:00:00.000' THEN 1 ELSE 0 END) Abandoned,
(SUM(CASE WHEN I.ServiceEnd = '00:00:00.000' THEN 1 ELSE 0 END) *100)/COUNT(I.Id) AbandonedPercent
FROM Location L
INNER JOIN Interaction I
ON L.Id = I.IdLocation
GROUP BY L.Id,L.Description
and need to calculate
Average Abandon Time,Members,Repeat Members,Repeat Visits,Repeat/Interaction,Average Wait,Average Service
Above first query is for Average Abandon Time
I think this is what you want:
SELECT L.Id, L.Description,
SUM(DATEDIFF(SECOND, servicestart, CheckinTime)) as abondendedTime
FROM Location L INNER JOIN
Interaction I
ON L.Id = I.IdLocation
WHERE ServiceEnd = '00:00:00.000'
GROUP BY L.Id, L.Description;
Unlike your previous question, the column in the WHERE is different from the column used for the DATEDIFF().