Optimize SQL, same line multiple times in CASE - sql

I've written a SQL Servre stored procedure (SQL Server 2014) that looks at a certain column in a certain table, if the result is null I want to take the value from an other column.
I've ended up with writing this line twice:
(Select t_EC
from TTCIB
where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
and t_comp = '50')
Once to check if it is null.
And the second time to actually add the value to my result if it wasn't null.
Is there a way to optimize this? So that the system doesn't need to run this line twice? (it has ltrim function twice and rtrim function twice so it would be useful)
SELECT DISTINCT TOP 15
(SELECT t_EC
FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '18') as EC18,
CASE
WHEN (SELECT t_EC FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '50') IS NULL
THEN (SELECT t_EC
FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '51')
ELSE (SELECT t_EC
FROM TTCIB
WHERE rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item))
AND t_comp = '50')
END AS EC50,
RTRIM(t1.t_sern) AS SerialNumber, t1.t_item AS Item,
RTRIM(t1.t_desc) AS ItemDesc, t1.t_ofbp AS SoldToBP,
RTRIM(t2.t_nama) AS BPName, t1.t_cwte AS Warranty,
t1.t_dltm AS DeliveryTime, t_optm AS InstallationTime,
t_clst AS Cluster, ISNULL(t3.t_endt,'1970-01-01') AS EndDate,
t4.t_csig as ItemSignalCode, t5.t_dsca as ItemSignalCodeDesc
FROM
FnGetSerialNos(#SerialNumber, #MasterCompany) t1
INNER JOIN
ttccom100900 t2 ON t1.t_ofbp = t2.t_bpid
LEFT OUTER JOIN
ttsctm120900 t3 ON t1.t_term = t3.t_term
LEFT OUTER JOIN
ttcibd001900 t4 ON ltrim(t1.t_item) = ltrim(t4.t_item)
LEFT OUTER JOIN
ttcmcs018900 t5 ON t4.t_csig = t5.t_csig

Use an INNER JOIN to read all relevant values from TTCIB, and use a COALESCE() function instead of CASE WHEN ... END:
SELECT DISTINCT TOP 15
x.t_18 as EC18
,COALESCE(x.t_50, x.t_51) AS EC50
,RTRIM(t1.t_sern) AS SerialNumber
,t1.t_item AS Item
,RTRIM(t1.t_desc) AS ItemDesc
,t1.t_ofbp AS SoldToBP
,RTRIM(t2.t_nama) AS BPName
,t1.t_cwte AS Warranty
,t1.t_dltm AS DeliveryTime
,t_optm AS InstallationTime
,t_clst AS Cluster
, ISNULL(t3.t_endt,'1970-01-01') AS EndDate
,t4.t_csig as ItemSignalCode
, t5.t_dsca as ItemSignalCodeDesc
FROM FnGetSerialNos(#SerialNumber, #MasterCompany) t1
INNER JOIN (
SELECT RTRIM(LTRIM(t_EC)) AS t_EC
,MAX(CASE WHEN t_comp = '18' THEN t_EC END) AS t_18
,MAX(CASE WHEN t_comp = '50' THEN t_EC END) AS t_50
,MAX(CASE WHEN t_comp = '51' THEN t_EC END) AS t_51
FROM TTCIB
GROUP BY t_EC
) x
ON RTRIM(LTRIM(t1.t_item)) = x.t_EC
INNER JOIN ttccom100900 t2
ON t1.t_ofbp = t2.t_bpid
LEFT OUTER JOIN ttsctm120900 t3
ON t1.t_term = t3.t_term
Left Outer JOIN ttcibd001900 t4
ON ltrim(t1.t_item) = ltrim(t4.t_item)
Left Outer JOIN ttcmcs018900 t5
ON t4.t_csig = t5.t_csig
;

faster(for all kinds of db)
coalesce((Select t_EC from TTCIB where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item)) and t_comp = '50'),(Select t_EC from TTCIB where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item)) and t_comp = '51')) as EC50
fastest(only for sqlserver, oracle with this method is quite complex)
(Select top 1 t_EC from TTCIB where rtrim(ltrim(t_item)) = rtrim(ltrim(t1.t_item)) and t_comp in ('50','51') order by t_comp asc) as EC50

Related

SQL CASE with multiple join

I am trying to run a sql select code as below. I am trying to fetch the trans_date which will either be in asutrans or asuhistr. But the below code doesnt give me any value and nor does it fail.
Do you think we can use CASE statement like that?
SELECT
v.voucher_no,
CASE
WHEN t.voucher_no = v.voucher_no THEN t.trans_date
ELSE t1.trans_date
END AS valuedate
FROM
aipdethis v
JOIN asutrans t ON t.client = v.client and t.voucher_no = v.voucher_no
JOIN asuhistr t1 ON t1.client = v.client and t1.voucher_no = v.voucher_no
WHERE
v.voucher_no ='22094200'
If I run the codes separately, then it does give me the result from asihistr. As below-
SELECT
v.voucher_no, t1.trans_Date FROM aipdethis v
JOIN asuhistr t1 ON t1.client = v.client and t1.voucher_no = v.voucher_no
WHERE
v.voucher_no ='22094200'
You cannot have case statement which checks voucher_no because you are already joining in the join query. I think this is what you're expecting:
select
v.voucher_no,
CASE
WHEN t.trans_date is null then t1.trans_date
ELSE t.trans_date
END AS valuedate
FROM aipdethis v
JOIN asutrans t ON t.client = v.client and t.voucher_no = v.voucher_no
JOIN asuhistr t1 ON t1.client = v.client and t1.voucher_no = v.voucher_no
where v.voucher_no ='22094200';

How to count the times a particular item appears in a query output

I have a query with a lot of tables and joins. So a simple Count(column) and Group By isn't working correctly.
The query returns an item list. I want to calculate how many times each item appears in that list.
Here's my query:
SELECT DECODE(BOM.ORGANIZATION_ID,203, 'CEC', 328, '3PL', 204, 'SIM') ORGANIZATION_CODE,
BOM.ORGANIZATION_ID,
MSI.SEGMENT1 "PARENT_ITEM",
MSIC.SEGMENT1 "COMPONENT_ITEM",
SUM(NVL(MMT.TRANSACTION_QUANTITY,0)) * NVL(SUM(CIC.ITEM_COST),0) "ANNUAL_MONEY",
SUM(NVL(MMT.TRANSACTION_QUANTITY,0)) "ANNUAL_QTY_USG",
NVL(SUM(CIC.ITEM_COST),0) "AVG_COST",
SUM(NVL(MSI.POSTPROCESSING_LEAD_TIME,0) + NVL(MSI.PREPROCESSING_LEAD_TIME,0)) LEAD_TIME
FROM BOM_BILL_OF_MATERIALS BOM
LEFT JOIN MTL_SYSTEM_ITEMS MSI
ON MSI.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MSI.INVENTORY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND MSI.ENABLED_FLAG = 'Y'
AND MSI.BOM_ENABLED_FLAG = 'Y'
LEFT JOIN CST_ITEM_COSTS CIC
ON CIC.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND CIC.INVENTORY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND CIC.COST_TYPE_ID = 1
LEFT JOIN MTL_MATERIAL_TRANSACTIONS MMT
ON MMT.INVENTORY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND MMT.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MMT.TRANSACTION_TYPE_ID IN (33,34,17)
LEFT JOIN MTL_TRANSACTION_TYPES MTT
ON MTT.TRANSACTION_TYPE_ID = MTT.TRANSACTION_TYPE_ID
LEFT JOIN BOM_INVENTORY_COMPONENTS BIC
ON BIC.BILL_SEQUENCE_ID = BOM.COMMON_BILL_SEQUENCE_ID
AND NVL(bic.disable_date, sysdate+1) > sysdate
LEFT JOIN BOM_COMPONENTS_B BCB
ON BIC.COMPONENT_SEQUENCE_ID = BCB.COMPONENT_SEQUENCE_ID
LEFT JOIN BOM_STRUCTURES_B BSB
ON BCB.BILL_SEQUENCE_ID = BSB.BILL_SEQUENCE_ID
LEFT JOIN MFG_LOOKUPS ML
ON ML.LOOKUP_CODE = BIC.WIP_SUPPLY_TYPE
AND ML.LOOKUP_CODE = BIC.ENFORCE_INT_REQUIREMENTS
AND ML.LOOKUP_TYPE = 'MTL_EAM_ITEM_TYPE'
LEFT JOIN MTL_SYSTEM_ITEMS MSIC
ON MSIC.ORGANIZATION_ID = BOM.ORGANIZATION_ID
AND MSIC.INVENTORY_ITEM_ID = BIC.COMPONENT_ITEM_ID
LEFT JOIN BOM_OPERATIONAL_ROUTINGS BOR
ON BOR.ASSEMBLY_ITEM_ID = BOM.ASSEMBLY_ITEM_ID
AND BOR.ORGANIZATION_ID = BOM.ORGANIZATION_ID
WHERE BOM.ORGANIZATION_ID = NVL(:P_ORG_ID,BOM.ORGANIZATION_ID)
AND EXISTS
(SELECT 'X'
FROM MTL_MATERIAL_TRANSACTIONS MMT
WHERE MMT.TRANSACTION_DATE >= ADD_MONTHS (SYSDATE,-12)
AND MSI.INVENTORY_ITEM_ID IS NOT NULL
)
GROUP BY BOM.ORGANIZATION_ID,
MSI.SEGMENT1,
MSIC.SEGMENT1
ORDER BY ORGANIZATION_CODE,
MSIC.SEGMENT1
My output is like this now:
I want to have another column which counts each item occurence in the output.
That's called conditional aggregation and you can do it with CASE EXPRESSION :
SELECT <col1>,<col2>..,
COUNT(CASE WHEN column ='Specific Val' THEN 1 END) as cnt
FROM YourTable
GROUP BY <col1>,<col2>..,
In MySQL this is also fine:
SUM(column = 'Specific Val')
Because expressions are treated as 1 and 0 .
wouldn't count(distinct column) work here since you're already using a group by
Would this be what you are looking for:
SELECT ColumnName, COUNT(*)
FROM TableName
GROUP BY ColumnName;
On the location of TableName you can also use a (SELECT ....).
You can also try this:
select count(*) from
(your query)
where column='value to be checked'

Show unique value for id, based on latest createby date

I am using the following SQL code to JOIN a few tables, but need to show unique values for the s.incidentid based on the latest s.createdate.
I know I need to use a Sub query with Maxdate, but I am not sure on the correct syntax.
This is my first query with multiple joins and I am struggling to get my head round it.
Here is my code:
SELECT
s.incidentid,
u.internalid as AssignedTo,
u.fullname as AssignedTo_FullName,
s.createby as AssignedBy,
u2.fullname as AssignedBy_FullName,
s.createdate as AssignedTime,
i.[description],
i.fix,
st.[description] as [Status],
(SELECT (CASE WHEN u.internalid = s.createby THEN 'Yes' ELSE 'No' END) as SelfAssigned),
d.d1,
d.d2,
d.d3,
d.d4,
d.d5
FROM dbo.IncidentServiceLevelAgreement s
JOIN dbo.UserAll u on u.userid = s.userid
JOIN dbo.UserAll u2 on u2.internalid = s.createby
JOIN dbo.IncidentAll i on s.incidentid = i.incidentid
JOIN dbo.[Status] st on i.statusid = st.statusid
JOIN dbo.flatdiagnosis d on i.actualdiagnosisid = d.diagnosisid
WHERE (s.groupId = '4954' and s.incidentServiceLevelAgreementTypeID = '9')
ORDER BY AssignedTime DESC
Any help greatly appreciated.
The easiest is to use a CTE and the ROW_NUMBER function:
WITH CTE AS
(
SELECT RN = ROW_NUMBER() OVER ( PARTITION BY incidentid
ORDER BY createdate DESC ),
s.Incidentid,
u.Internalid AS AssignedTo,
u.Fullname AS AssignedTo_FullName,
s.Createby AS AssignedBy,
u2.Fullname AS AssignedBy_FullName,
s.Createdate AS AssignedTime,
i.[Description],
i.Fix,
st.[Description] AS [Status],
SelfAssigned = CASE WHEN u.Internalid = s.Createby
THEN 'Yes' ELSE 'No' END,
d.D1,
d.D2,
d.D3,
d.D4,
d.D5
FROM dbo.Incidentservicelevelagreement s
JOIN dbo.Userall u
ON u.Userid = s.Userid
JOIN dbo.Userall u2
ON u2.Internalid = s.Createby
JOIN dbo.Incidentall i
ON s.Incidentid = i.Incidentid
JOIN dbo.[Status] st
ON i.Statusid = st.Statusid
JOIN dbo.Flatdiagnosis d
ON i.Actualdiagnosisid = d.Diagnosisid
WHERE ( s.Groupid = '4954'
AND s.Incidentservicelevelagreementtypeid = '9' )
)
SELECT * FROM CTE WHERE RN = 1
ORDER BY AssignedTime DESC
(instead of SELECT * list all columns explicitly, I didn't feel like it)

Invoke a column twice with different conditions

I really appreciate any help with this matter :)
Am Working on a Report now and I had faced some troubles
I have this Query and it work fine , now I want to add a coulmn that is already exist in the query(from the same table) , but this time i'll change the condition of it , BTW the conditions in both of the 2 column are based on one other column
like for example If I have this :
Select Price from ITM1 WHERE PriceList = '1'
and also this
Select Price from ITM1 WHERE PriceList = '10'
how I can write in the same query and let them display in two different column ?
I will put the Query here in case if some one can help me through it :
you can see THE Column Price & PriceList in the lower part of it ,Bolded.
I just need to make the samething again but with a new coulmn name thats it.
Using the IN Operator will give you what you want. However, there are other changes that you can make to your query which would boost performance - but it's out of scope to the question. I'm unclear as to what you're trying to do with the different "columns" Please help explain. Else see #Dave.Gugg's answer which does just that.
SELECT T0.ItemCode,
T0.ItemName,
T0.CardCode,
T0.CodeBars,
T2.UgpCode,
T3.AltQty,
T3.BaseQty,
CASE
WHEN T4.Uomentry = - 1
THEN T0.[BuyUnitMsr]
ELSE t4.UomName
END AS 'UoMName',
T4.UomEntry,
T0.U_CAT_CODE,
T0.U_CAT_NAME,
T1.CardName,
(
SELECT TOP (1) dbo.PDN1.U_AC_QTY_ORDER
FROM dbo.PDN1
INNER JOIN dbo.OPDN ON dbo.PDN1.DocEntry = dbo.OPDN.DocEntry
WHERE (dbo.PDN1.ItemCode = T0.ItemCode)
AND (dbo.OPDN.CardCode = T0.CardCode)
ORDER BY dbo.OPDN.DocDate DESC
) AS OQuantity,
(
SELECT TOP (1) PDN1_1.U_AC_QTY_BONUS
FROM dbo.PDN1 AS PDN1_1
INNER JOIN dbo.OPDN AS OPDN_1 ON PDN1_1.DocEntry = OPDN_1.DocEntry
WHERE (PDN1_1.ItemCode = T0.ItemCode)
AND (OPDN_1.CardCode = T0.CardCode)
ORDER BY OPDN_1.DocDate DESC
) AS BQuantity,
ITM1.Price,
T0.U_DISC_PER
FROM dbo.OITM AS T0
INNER JOIN dbo.OCRD AS T1 ON T0.CardCode = T1.CardCode
INNER JOIN dbo.OUGP AS T2 ON T0.UgpEntry = T2.UgpEntry
INNER JOIN dbo.UGP1 AS T3 ON T2.UgpEntry = T3.UgpEntry
INNER JOIN dbo.ITM1 ON T0.ItemCode = dbo.ITM1.ItemCode
AND dbo.ITM1.PriceList IN ('1', '10')
LEFT JOIN dbo.OUOM AS T4 ON T3.UomEntry = T4.UomEntry
WHERE (T0.Series = '65')
AND (
T4.UomEntry = 3
OR T4.UomEntry = '-1'
)
If you want a different column (this may perform better than two joins):
SELECT T0.ItemCode,
T0.ItemName,
T0.CardCode,
T0.CodeBars,
T2.UgpCode,
T3.AltQty,
T3.BaseQty,
CASE
WHEN T4.Uomentry = - 1
THEN T0.[BuyUnitMsr]
ELSE t4.UomName
END AS 'UoMName',
T4.UomEntry,
T0.U_CAT_CODE,
T0.U_CAT_NAME,
T1.CardName,
(
SELECT TOP (1) dbo.PDN1.U_AC_QTY_ORDER
FROM dbo.PDN1
INNER JOIN dbo.OPDN ON dbo.PDN1.DocEntry = dbo.OPDN.DocEntry
WHERE (dbo.PDN1.ItemCode = T0.ItemCode)
AND (dbo.OPDN.CardCode = T0.CardCode)
ORDER BY dbo.OPDN.DocDate DESC
) AS OQuantity,
(
SELECT TOP (1) PDN1_1.U_AC_QTY_BONUS
FROM dbo.PDN1 AS PDN1_1
INNER JOIN dbo.OPDN AS OPDN_1 ON PDN1_1.DocEntry = OPDN_1.DocEntry
WHERE (PDN1_1.ItemCode = T0.ItemCode)
AND (OPDN_1.CardCode = T0.CardCode)
ORDER BY OPDN_1.DocDate DESC
) AS BQuantity,
CASE
WHEN ITM1.PriceList = '1'
THEN ITM1.Price
ELSE '0'
END AS Price1,
CASE
WHEN ITM1.PriceList = '10'
THEN ITM1.Price
ELSE '0'
END AS Price2,
T0.U_DISC_PER
FROM dbo.OITM AS T0
INNER JOIN dbo.OCRD AS T1 ON T0.CardCode = T1.CardCode
INNER JOIN dbo.OUGP AS T2 ON T0.UgpEntry = T2.UgpEntry
INNER JOIN dbo.UGP1 AS T3 ON T2.UgpEntry = T3.UgpEntry
INNER JOIN dbo.ITM1 ON T0.ItemCode = dbo.ITM1.ItemCode
AND dbo.ITM1.PriceList IN ('1', '10')
LEFT JOIN dbo.OUOM AS T4 ON T3.UomEntry = T4.UomEntry
WHERE (T0.Series = '65')
AND (
T4.UomEntry = 3
OR T4.UomEntry = '-1'
)
You should be able to just join to the table a second time, but you will need to make the joins outer:
SELECT T0.ItemCode ,
T0.ItemName ,
T0.CardCode ,
T0.CodeBars ,
T2.UgpCode ,
T3.AltQty ,
T3.BaseQty ,
CASE WHEN T4.Uomentry = -1 THEN T0.[BuyUnitMsr]
ELSE t4.UomName
END AS 'UoMName' ,
T4.UomEntry ,
T0.U_CAT_CODE ,
T0.U_CAT_NAME ,
T1.CardName ,
( SELECT TOP ( 1 )
dbo.PDN1.U_AC_QTY_ORDER
FROM dbo.PDN1
INNER JOIN dbo.OPDN ON dbo.PDN1.DocEntry = dbo.OPDN.DocEntry
WHERE ( dbo.PDN1.ItemCode = T0.ItemCode )
AND ( dbo.OPDN.CardCode = T0.CardCode )
ORDER BY dbo.OPDN.DocDate DESC
) AS OQuantity ,
( SELECT TOP ( 1 )
PDN1_1.U_AC_QTY_BONUS
FROM dbo.PDN1 AS PDN1_1
INNER JOIN dbo.OPDN AS OPDN_1 ON PDN1_1.DocEntry = OPDN_1.DocEntry
WHERE ( PDN1_1.ItemCode = T0.ItemCode )
AND ( OPDN_1.CardCode = T0.CardCode )
ORDER BY OPDN_1.DocDate DESC
) AS BQuantity ,
dbo.ITM1.Price ,
ITM1Second.Price,
T0.U_DISC_PER
FROM dbo.OITM AS T0
INNER JOIN dbo.OCRD AS T1 ON T0.CardCode = T1.CardCode
INNER JOIN dbo.OUGP AS T2 ON T0.UgpEntry = T2.UgpEntry
INNER JOIN dbo.UGP1 AS T3 ON T2.UgpEntry = T3.UgpEntry
LEFT OUTER JOIN dbo.ITM1 ON T0.ItemCode = dbo.ITM1.ItemCode
AND dbo.ITM1.PriceList = '10'
LEFT OUTER JOIN dbo.ITM1 ITM1Second ON T0.ItemCode = ITM1Second.ItemCode
AND ITM1Second.PriceList = '1'
LEFT OUTER JOIN dbo.OUOM AS T4 ON T3.UomEntry = T4.UomEntry
WHERE ( T0.Series = '65' )
AND ( T4.UomEntry = 3
OR T4.UomEntry = '-1'
)

sql COUNT question

How can I modify this query to return results that exclude all records that have a duplicate DocNum?
SELECT IdEntry, DocNum, CardCode, QUOTENAME(CardName,'"'),
Convert(Decimal(10,2),PayAmount), Convert(Decimal(10,2),InvPayAmnt),
CONVERT(VARCHAR(10), T5.PmntDate,101), NumAtCard, PymMeth, ObjType
FROM DELAWARE.dbo.PWZ3
INNER JOIN OPWZ T5 ON T5.IdNumber = IdEntry
WHERE T5.PmntDate = '3/10/2011'
AND T5.Canceled = 'N'
AND Checked = 'Y'
Try
WITH
dups (DocNum)
AS (
SELECT DocNum
FROM DELAWARE.dbo.PWZ3
GROUP BY DocNum
HAVING COUNT(1) > 1
)
SELECT PWZ3.IdEntry, PWZ3.DocNum, PWZ3.CardCode, QUOTENAME(CardName,'"'),
Convert(Decimal(10,2),PayAmount), Convert(Decimal(10,2),InvPayAmnt),
CONVERT(VARCHAR(10), T5.PmntDate,101), NumAtCard, PymMeth, ObjType
FROM DELAWARE.dbo.PWZ3 PWZ3
INNER JOIN OPWZ T5 ON T5.IdNumber = PWZ3.IdEntry
LEFT JOIN Dups ON DUPS.DocNum = PWZ3.DocNum
WHERE T5.PmntDate = '3/10/2011'
AND T5.Canceled = 'N'
AND Checked = 'Y'
AND Dups.DocNum is null
(I might not have all the column aliases right)
I'm not sure I understood all the query, but doesn't a simple
SELECT ... GROUP BY docNum
suffice?
SELECT IdEntry, DocNum, CardCode, QUOTENAME(CardName,'"'),
Convert(Decimal(10,2),PayAmount), Convert(Decimal(10,2),InvPayAmnt),
CONVERT(VARCHAR(10), T5.PmntDate,101), NumAtCard, PymMeth, ObjType
FROM DELAWARE.dbo.PWZ3
INNER JOIN OPWZ T5 ON T5.IdNumber = IdEntry
JOIN (SELECT min(IdEntry) as minIdEntry from DELAWARE.dbo.PWZ3 group by DocNum) tmp on DELAWARE.dbo.PWZ3.IdEntry = minIdEntry
WHERE T5.PmntDate = '3/10/2011'
AND T5.Canceled = 'N'
AND Checked = 'Y'