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

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;

Related

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.

SQL Error when using LIKE CASE WHEN with subquery

I'm attempting to write an SQL statement that use Excel parameters to insert data via a drop down menu. This normally works great, but I think because I'm using a subquery in this case I'm getting the error "The multi-part identifier could not be bound." The subquery is used to create a sum of the quantity of an item purchased within the past week. Here's the code:
SELECT DISTINCT ITMMASTER.ITMREF_0 AS ITEMCODE, ITMMASTER.ITMDES1_0 AS ITEMDESC, Sum(ITMMVT.PHYSTO_0) AS AVAILSTOCK, Sum(ITMMVT.ORDSTO_0) AS ONORDER, Sum(ITMMVT.PHYALL_0) AS ALLOCATED, Sum(ITMFACILIT.MAXSTO_0) AS MAX,
INVQTY = (SELECT Sum(SINVOICED.QTY_0) AS INVQTY
FROM x3v11.PROD.SINVOICED SINVOICED
WHERE SINVOICED.INVDAT_0 BETWEEN DATEADD(WEEK,-1,DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE()),0))
AND DATEADD(DAY,4,DATEADD(WEEK,-1,DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE()),0)))
AND SINVOICED.ITMREF_0 = ITMMASTER.ITMREF_0
),
ITMMASTER.ITMWEI_0 AS WEIGHT, ITMCOST.CSTTOT_0 AS COST, ITMBPS.BPSNUM_0 AS VENDOR, BPSUPPLIER.BPSNAM_0 AS VENDNAME, ITMMASTER.TSICOD_2 AS CAT
FROM x3v11.PROD.ITMMASTER ITMMASTER
LEFT OUTER JOIN x3v11.PROD.ITMMVT ITMMVT ON ITMMASTER.ITMREF_0 = ITMMVT.ITMREF_0
LEFT OUTER JOIN x3v11.PROD.ITMFACILIT ITMFACILIT ON ITMMVT.ITMREF_0 = ITMFACILIT.ITMREF_0 AND ITMMVT.STOFCY_0 = ITMFACILIT.STOFCY_0
LEFT OUTER JOIN x3v11.PROD.ITMCOST ITMCOST ON ITMMVT.ITMREF_0 = ITMCOST.ITMREF_0 AND ITMMVT.STOFCY_0 = ITMCOST.STOFCY_0
LEFT OUTER JOIN x3v11.PROD.ITMBPS ITMBPS ON ITMMASTER.ITMREF_0 = ITMBPS.ITMREF_0
LEFT OUTER JOIN x3v11.PROD.BPSUPPLIER BPSUPPLIER ON ITMBPS.BPSNUM_0 = BPSUPPLIER.BPSNUM_0
WHERE ITMCOST.STOFCY_0 <> '115'
AND ITMFACILIT.MAXSTO_0 <> 0
AND ITMBPS.PIO_0 <> 99
AND ITMBPS.BPSNUM_0 LIKE CASE WHEN ? IS NOT NULL THEN ? ELSE '%' END
GROUP BY ITMMASTER.ITMREF_0, ITMMASTER.ITMDES1_0, ITMMASTER.ITMWEI_0, ITMCOST.CSTTOT_0, ITMBPS.BPSNUM_0, BPSUPPLIER.BPSNAM_0, ITMMASTER.TSICOD_2
ORDER BY ITMMASTER.ITMREF_0
I think you have specified the syntax for the subquery incorrectly:
INVQTY = (SELECT Sum(SINVOICED.QTY_0) AS INVQTY
FROM x3v11.PROD.SINVOICED SINVOICED
WHERE SINVOICED.INVDAT_0 BETWEEN
DATEADD(WEEK,-1,DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE()),0))
AND DATEADD(DAY,4,DATEADD(WEEK,-1,DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE()),0)))
AND SINVOICED.ITMREF_0 = ITMMASTER.ITMREF_0
),
I think it should be:
(SELECT Sum(SINVOICED.QTY_0)
FROM x3v11.PROD.SINVOICED SINVOICED
WHERE SINVOICED.INVDAT_0 BETWEEN
DATEADD(WEEK,-1,DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE()),0))
AND DATEADD(DAY,4,DATEADD(WEEK,-1,DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE()),0)))
AND SINVOICED.ITMREF_0 = ITMMASTER.ITMREF_0
) AS INVQTY,

How to use a non-existing column in sql query

I am working in SQL server 2012. I have to write a sql statement where I first assign a value to [Pay_Type], which is a non-existing column (not sure whether it can be called as variable or not) and based upon its value I want to use it in another case statement as shown below
SELECT sp.First_Name, [Pay_Type] = CASE WHEN NOT EXISTS(SELECT '1' FROM
PERSON_SALARY ps WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL)
THEN 'Hourly' ELSE 'Salary' END,
HOURLY_RATE = CASE WHEN [Pay_Type] = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END
FROM SEC_PERSON sp
LEFT OUTER JOIN PERSON_JOB pj ON sp.PERSON_ID = pj.PERSON_ID
WHERE sp.END_DATE IS NOT NULL
But I am getting "Invalid column name 'Pay_Type' " error.
Column aliases cannot be re-used in the same SELECT where they are define. The typical answer is to use a subquery or CTE. I also like using a lateral join:
SELECT sp.First_Name, s.Pay_Type,
HOURLY_RATE = (CASE WHEN s.Pay_Type = 'Hourly' THEN pj.HOURLY_RATE ELSE
'0.00' END)
FROM SEC_PERSON sp LEFT OUTER JOIN
PERSON_JOB pj
ON sp.PERSON_ID = pj.PERSON_ID OUTER APPLY
(SELECT (CASE WHEN NOT EXISTS (SELECT 1
FROM PERSON_SALARY ps
WHERE ps.PARTY_ID = sp.PARTY_ID and ps.END_DATE IS NULL
)
THEN 'Hourly' ELSE 'Salary'
END) as PayType
) s
WHERE sp.END_DATE IS NOT NULL

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.

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

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.