SQL Server query with CASE and GROUP BY, field invalid? - sql

Can't figure out what I'm doing wrong here. It says field HasNoteDate is invalid. I just want it to return 1 if there's a date, 0 if there's not and I wanted it grouped so I can get the counts and the sum of loan amounts. I've looked at the stackoverflow answers for grouping by a case and none of them are solving it for me. Thanks!
SELECT dbo.BDONAMES.UserID, dbo.BRKRMAST.Tier, dbo.BDONAMES.REGION, COUNT(*) AS TierRegionCount,
SUM(dbo.LOAN.LOAN_AMT) AS LoanAmtSum, dbo.LOAN.DEAL_STATUS, CASE WHEN dbo.WORKFLOW.NOTE_DATE IS NULL
THEN 0 ELSE 1 END AS HasNoteDate
FROM dbo.BRKRMAST INNER JOIN
dbo.BRKRREF ON dbo.BRKRMAST.BRKRMASTID = dbo.BRKRREF.BRKRMASTID INNER JOIN
dbo.LOAN ON dbo.BRKRREF.LoanId = dbo.LOAN.LoanId INNER JOIN
dbo.WORKFLOW ON dbo.LOAN.LoanId = dbo.WORKFLOW.LoanId LEFT OUTER JOIN
dbo.BDONAMES ON dbo.BRKRMAST.BDONAMESID = dbo.BDONAMES.BDONAMESID
WHERE (LEN(dbo.BDONAMES.UserID) > 0) AND (dbo.BRKRMAST.Tier > 0) AND (LEN(dbo.BDONAMES.REGION) > 0)
GROUP BY dbo.BDONAMES.UserID, dbo.BRKRMAST.Tier, dbo.BDONAMES.REGION, dbo.LOAN.LOAN_AMT, dbo.LOAN.DEAL_STATUS, HasNoteDate
ORDER BY dbo.BDONAMES.UserID, dbo.BRKRMAST.Tier, dbo.BDONAMES.REGION

logic of SQL query execution is not straightforward as common programming languages
here are sample execution stages for your query:
perform join on tables in FROM CLAUSE
perform GROUP BY - this will cause error, as HasNoteDate is not defined for this moment
perform ORDER BY
perform SELECT - only during this stage column HasNoteDate is defined
so, you cannot use undefined column HasNoteDate in GROUP BY, you have to replace it with your statement (CASE WHEN dbo.WORKFLOW.NOTE_DATE IS NULL THEN 0 ELSE 1 END), then sql server will be able to GROUP

SELECT dbo.BDONAMES.UserID, dbo.BRKRMAST.Tier, dbo.BDONAMES.REGION, COUNT(*) AS TierRegionCount,
SUM(dbo.LOAN.LOAN_AMT) AS LoanAmtSum, dbo.LOAN.DEAL_STATUS, CASE WHEN dbo.WORKFLOW.NOTE_DATE IS NULL
THEN 0 ELSE 1 END AS HasNoteDate
FROM dbo.BRKRMAST INNER JOIN
dbo.BRKRREF ON dbo.BRKRMAST.BRKRMASTID = dbo.BRKRREF.BRKRMASTID INNER JOIN
dbo.LOAN ON dbo.BRKRREF.LoanId = dbo.LOAN.LoanId INNER JOIN
dbo.WORKFLOW ON dbo.LOAN.LoanId = dbo.WORKFLOW.LoanId LEFT OUTER JOIN
dbo.BDONAMES ON dbo.BRKRMAST.BDONAMESID = dbo.BDONAMES.BDONAMESID
WHERE (LEN(dbo.BDONAMES.UserID) > 0) AND (dbo.BRKRMAST.Tier > 0) AND (LEN(dbo.BDONAMES.REGION) > 0)
GROUP BY dbo.BDONAMES.UserID, dbo.BRKRMAST.Tier, dbo.BDONAMES.REGION, dbo.LOAN.DEAL_STATUS, CASE WHEN dbo.WORKFLOW.NOTE_DATE IS NULL
THEN 0 ELSE 1 END
ORDER BY dbo.BDONAMES.UserID, dbo.BRKRMAST.Tier, dbo.BDONAMES.REGION
Use columns in your group by exactly the way you have defined in you select Statement, otherwise SQL server tries to GROUP it with the fields that it cannot find in SELECT statement and throws an error.

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;

Group by + Select Case

I try to query this code but i got the error massage.
"ORA-00979: not a GROUP BY expression"
Can we use case SUM and Max in group by function.
SELECT PLAN.MFGNO "MFGNO",
PROCESSMASTER.PART_NO "PART_NO",
PROCESS.MED_PROC_CD "M_PROCESS",
MAX(PLAN.PLAN_START) "PLAN_START_DATE",
MAX(PLAN.PLAN_END) "PLAN_END_DATE",
MAX(PLAN.ACT_START) "ACT_START_DATE",
MAX(PLAN.ACT_END) "ACT_END_DATE",
(CASE WHEN PROCESSMASTER.COMP_FLG =1 AND PROCESS.MED_PROC_CD='OUT-P' THEN SUM(SUB_PRO.HACYUKIN)
ELSE MAX(SUB_PRO.HACYUKIN)
END) "SUB_TOTAL_PRICE",
--SUM(SUB_PRO.HACYUKIN) "SUB_TOTAL_PRICE",
MAX(SUB_PRO.SICD) "SUB_CODE",
MAX(PROCESSMASTER.PROC_REM) "DE_PROCESS"
FROM T_PLANDATA PLAN
INNER JOIN T_PROCESSNO PROCESSMASTER
ON PLAN.BARCODE = PROCESSMASTER.BARCODE
INNER JOIN T_PLANNED_PROCESS PROCESS
ON PROCESSMASTER.PROCESS_CD = PROCESS.PLAN_PROC_CD
INNER JOIN KEIKAKUMST SUB_PRO
ON PROCESSMASTER.BARCODE = SUB_PRO.KMSEQNO
WHERE PLAN.MFGNO ='T21-F2D1-10034'
GROUP BY PLAN.MFGNO,
PROCESSMASTER.PART_NO,
PROCESS.MED_PROC_CD;
Can we use case SUM and Max in group by function.
Yes
However, your problem is that you use PROCESSMASTER.COMP_FLG =1 AND PROCESS.MED_PROC_CD = 'OUT-P' inside the CASE expression and neither PROCESSMASTER.COMP_FLG nor PROCESS.MED_PROC_CD are in the GROUP BY clause or inside of an aggregation function.
You either want:
SELECT PLAN.MFGNO "MFGNO",
PROCESSMASTER.PART_NO "PART_NO",
PROCESS.MED_PROC_CD "M_PROCESS",
MAX(PLAN.PLAN_START) "PLAN_START_DATE",
MAX(PLAN.PLAN_END) "PLAN_END_DATE",
MAX(PLAN.ACT_START) "ACT_START_DATE",
MAX(PLAN.ACT_END) "ACT_END_DATE",
(CASE WHEN PROCESSMASTER.COMP_FLG =1 AND PROCESS.MED_PROC_CD='OUT-P' THEN SUM(SUB_PRO.HACYUKIN)
ELSE MAX(SUB_PRO.HACYUKIN)
END) "SUB_TOTAL_PRICE",
--SUM(SUB_PRO.HACYUKIN) "SUB_TOTAL_PRICE",
MAX(SUB_PRO.SICD) "SUB_CODE",
MAX(PROCESSMASTER.PROC_REM) "DE_PROCESS"
FROM T_PLANDATA PLAN
INNER JOIN T_PROCESSNO PROCESSMASTER
ON PLAN.BARCODE = PROCESSMASTER.BARCODE
INNER JOIN T_PLANNED_PROCESS PROCESS
ON PROCESSMASTER.PROCESS_CD = PROCESS.PLAN_PROC_CD
INNER JOIN KEIKAKUMST SUB_PRO
ON PROCESSMASTER.BARCODE = SUB_PRO.KMSEQNO
WHERE PLAN.MFGNO ='T21-F2D1-10034'
GROUP BY PLAN.MFGNO,
PROCESSMASTER.PART_NO,
PROCESS.MED_PROC_CD,
PROCESSMASTER.COMP_FLG, -- Add to the group by clause
PROCESS.MED_PROC_CD -- Add to the group by clause
;
or something like:
SELECT PLAN.MFGNO "MFGNO",
PROCESSMASTER.PART_NO "PART_NO",
PROCESS.MED_PROC_CD "M_PROCESS",
MAX(PLAN.PLAN_START) "PLAN_START_DATE",
MAX(PLAN.PLAN_END) "PLAN_END_DATE",
MAX(PLAN.ACT_START) "ACT_START_DATE",
MAX(PLAN.ACT_END) "ACT_END_DATE",
CASE
WHEN MAX(PROCESSMASTER.COMP_FLG) = 1
AND COUNT(CASE WHEN PROCESS.MED_PROC_CD = 'OUT-P' THEN 1 END) > 0
THEN SUM(SUB_PRO.HACYUKIN)
ELSE MAX(SUB_PRO.HACYUKIN)
END "SUB_TOTAL_PRICE",
--SUM(SUB_PRO.HACYUKIN) "SUB_TOTAL_PRICE",
MAX(SUB_PRO.SICD) "SUB_CODE",
MAX(PROCESSMASTER.PROC_REM) "DE_PROCESS"
FROM T_PLANDATA PLAN
INNER JOIN T_PROCESSNO PROCESSMASTER
ON PLAN.BARCODE = PROCESSMASTER.BARCODE
INNER JOIN T_PLANNED_PROCESS PROCESS
ON PROCESSMASTER.PROCESS_CD = PROCESS.PLAN_PROC_CD
INNER JOIN KEIKAKUMST SUB_PRO
ON PROCESSMASTER.BARCODE = SUB_PRO.KMSEQNO
WHERE PLAN.MFGNO ='T21-F2D1-10034'
GROUP BY PLAN.MFGNO,
PROCESSMASTER.PART_NO,
PROCESS.MED_PROC_CD;
Note: this is untested as you have not provided a minimal representative example of your tables or data to test against.

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.

Inner join with count in select query

I am trying to get the query for details along with the status if the particular column exists for that report using the below query.
select rh.Rec_ID
,rh.Report_ID
,rh.Report_Name
,rh.Source_Type_Display
,rh.Description
,rh.IndID
,rh.Name
,rh.Time_Updated
,count(*) OVER() as TotalCount
,case when count(rd.demo) > 0 THEN 'Completed' ELSE 'incomplete' END
FROM v_Report_Header_OV rh
inner join v_Table_NI_Report_Demo rd
ON rh.Report_ID = rd.Report_ID
WHERE rh.Client_ID = 12324
I am getting below error
Column 'v_Report_Header_OV.Rec_ID' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.
I am not sure why i am getting error, Could any one please help on this
Many thanks in advance.
you missed group by
select rh.Rec_ID
,rh.Report_ID
,rh.Report_Name
,rh.Source_Type_Display
,rh.Description
,rh.IndID
,rh.Name
,rh.Time_Updated
,count(*) OVER() as TotalCount
,case when count(rd.demo) > 0 THEN 'Completed' ELSE 'incomplete' END
FROM v_Report_Header_OV rh
inner join v_Table_NI_Report_Demo rd
ON rh.Report_ID = rd.Report_ID
WHERE rh.Client_ID = 12324
group by rh.Rec_ID
,rh.Report_ID
,rh.Report_Name
,rh.Source_Type_Display
,rh.Description
,rh.IndID
,rh.Name
,rh.Time_Updated

How can I refactor this query

How can I rewrite this SQL code? I would like to avoid the repetitive execution of the case for every record.
SELECT chcr.chsid,
CASE
WHEN EXISTS
(SELECT 1
FROM hdr_run chre,
clmerr ce
WHERE chre.chsid = chcr.chsid
AND chre.run_nmbr < chcr.last_run_nmbr
AND chre.clm_error_sid = ce.clm_error_sid
GROUP BY chre.chsid
HAVING COUNT(chre.clm_error_sid) > 0
)
THEN 'Appended'
ELSE 'Never Appended'
END Run_Detail
FROM
clm_res chcr,
clm_der chde
WHERE chde.chsid = chcr.chsid
Have a look at that query please:
SELECT
chcr.chsid,
CASE
WHEN ce.clm_error_sid IS NOT NULL AND COUNT(chre.clm_error_sid, 0) > 0
THEN 'Appended'
ELSE 'Never Appended'
END Run_Detail
FROM
clm_res chcr
JOIN clm_der chde ON chde.chsid = chcr.chsid
LEFT JOIN hdr_run chre ON chre.chsid = chcr.chsid AND chre.run_nmbr < chcr.last_run_nmbr
LEFT JOIN clmerr ce ON chre.clm_error_sid = ce.clm_error_sid
GROUP BY chcr.chsid
If there's more than one clm_der for each clm_res based on their chsid, we'd have to double check that the COUNT is not counting the extras from clm_der.
I have no data to test this on so all I can go on is the SQL you've provided but from a brief look it does not appear that the GROUP BY and HAVING COUNT() > 0 statements are required as the combination of the INNER JOIN condition in the sub-query and the use of EXISTS in the outer query does the same thing.
Does this have exactly the same functionality:
SELECT chcr.chsid,
CASE
WHEN EXISTS
( SELECT 1
FROM hdr_run chre
INNER JOIN
clmerr ce
ON (chre.clm_error_sid = ce.clm_error_sid)
WHERE chre.chsid = chcr.chsid
AND chre.run_nmbr < chcr.last_run_nmbr
)
THEN 'Appended'
ELSE 'Never Appended'
END Run_Detail
FROM clm_res chcr
INNER JOIN
clm_der chde
ON ( chde.chsid = chcr.chsid );
SQLFIDDLE
Also, repeated execution of the CASE statement is not a bad thing as the optimizer should not duplicate executions of the sub-query.