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.
Related
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;
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.
I have the below SQL query, but the problem is that the WHERE statement is not working properly with RIGHT JOIN:
SELECT COUNT(*) no_of_application_by_status, applicationStatusName
FROM `Application` `a`
right JOIN `ApplicationStatus` `ass` ON `ass`.`applicationStatusId`=`a`.`applicationStatusId`
WHERE `applicationTypeId` = '40007'
GROUP BY `ass`.`applicationStatusId`
I want to get the applicationStatusName where no_of_application_by_status = 0
You have to put the where condition to the on clause:
SELECT COUNT(*) no_of_application_by_status, applicationStatusName
FROM `Application` `a`
right JOIN `ApplicationStatus` `ass` ON `ass`.`applicationStatusId`=`a`.`applicationStatusId`
and `applicationTypeId` = '40007'
GROUP BY `ass`.`applicationStatusId`
If you do not do it, the joind result will be filtered by the where condition.
Use Having you want to fetch group count = 0 OR if you want to count only the records where no_of_application_by_status = 0 then use AND condition in WHERE
For Group Count = 0
SELECT COUNT(*) no_of_application_by_status,
applicationStatusName
FROM Application a
RIGHT JOIN ApplicationStatus ass ON ass.applicationStatusId=a.applicationStatusId
WHERE applicationTypeId = '40007'
HAVING COUNT(*) = 0
GROUP BY ass.applicationStatusId
OR count of no_of_application_by_status = 0
SELECT COUNT(*) no_of_application_by_status,
applicationStatusName
FROM Application a
RIGHT JOIN ApplicationStatus ass ON ass.applicationStatusId=a.applicationStatusId
WHERE applicationTypeId = '40007' AND no_of_application_by_status = 0
GROUP BY ass.applicationStatusId
Given below is my select query in PostgreSQL
SELECT
gtab12.AcGrCode,
gtab12.AcId,
gtab12.AcName,
gtab11.AcgrName,
gtab16.VrDate,
gtab16.PDC,
cast(gtab16.VrDate as char(12)) as vdate,
gtab16.VrNo,
gtab16.Refno,
gtab02.VrName,
gtab17.Narr,
CASE WHEN gtab16.VrId = 6 THEN 0::decimal ELSE gtab17.Dr::decimal END AS Dr,
CASE WHEN gtab16.VrId = 6 THEN 0::decimal ELSE gtab17.Cr::decimal END AS Cr,
gtab16.AcyrId, gtab16.VrId,
coalesce(SUM(gtab17.Dr), 0::money) AS OpDr,
coalesce(SUM(gtab17.Cr), 0::money) AS OpCr ,
coalesce(SUM(gtab17.Dr), 0::money)AS OpperDr,
coalesce(SUM(gtab17.Cr), 0::money)AS OpperCr,
gtab47.AreaName,
gtab16.JrmId
FROM
gtab16
INNER JOIN gtab02 ON gtab16.VrId = gtab02.VrId
INNER JOIN gtab17 ON gtab16.JrMId = gtab17.JrmId
INNER JOIN gtab12 ON gtab17.AcId = gtab12.AcId
INNER JOIN gtab11 ON gtab12.AcGrCode = gtab11.AcgrCode
INNER JOIN gtab01 ON gtab16.AcyrId = gtab01.AcYrId
LEFT OUTER JOIN gtab22 ON gtab16.RepId = gtab22.RepId
LEFT OUTER JOIN gtab47 ON gtab12.AreaId = gtab47.AreaId
WHERE
(gtab17.AcId = gtab12.AcId) and gtab16.BranchID = 1 And vrdate Between
Cast('2014-04-01' AS timestamp) AND Cast('2014-09-27' AS timestamp) AND
(gtab16.AcYrId = 7) AND gtab16.VrId <> 6 And gtab12.acid <> 0
when executing am getting this error
ERROR: column "gtab12.acgrcode" must appear in the GROUP BY clause or
be used in an aggregate function
Note : before modifying this query the aggreagte functions are gathering from sub selects see it here
You are using aggregate functions (SUM) in some columns so you need to use aggregates functions on other ones or group by columns.
Bye, David.
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.