SQL CASE returning wrong values - sql

I wrote the following query but the CASE statements are returning incorrect values. When soaddr has a value instead of returning the value from soaddr it will return the incorrect value from arcust. But if I change the else statment to pull the value from soaddr then it will return a NULL value. What am I doing wrong?
SELECT DISTINCT a.custno, b.company,
CASE WHEN c.address1 = NULL THEN b.address1
ELSE b.address1
END as address,
CASE WHEN c.city = NULL THEN b.city
ELSE b.city
END as city,
CASE WHEN c.addrstate = NULL THEN b.addrstate
ELSE b.addrstate
END as addrstate,
CASE WHEN c.zip = NULL THEN b.zip
ELSE b.zip
END as zip,
invno, descrip, qtyshp, price, extprice, b.tax, invdte
FROM artran a
LEFT JOIN arcust b ON a.custno = b.custno
LEFT JOIN soaddr c ON a.custno = c.custno

You can't compare a value to NULL with =.
Use is null instead.
CASE WHEN c.address1 IS NULL THEN b.address1
ELSE b.address1

The reason it is returning the wrong value is that your case statement is setup to always return the arcust value because all parts of the THEN & ELSE reference the b table alias which points to arcust. Between that and comparing the null incorrectly as #ServerSentinel appropriately points out you are not getting your desired results. Modify your query as follows to point to the c table alias and compare the null as IS NULL
SELECT DISTINCT a.custno, b.company,
CASE WHEN c.address1 IS NULL THEN b.address1
ELSE c.address1
END as address,
CASE WHEN c.city IS NULL THEN b.city
ELSE c.city
END as city,
CASE WHEN c.addrstate IS NULL THEN b.addrstate
ELSE c.addrstate
END as addrstate,
CASE WHEN c.zip IS NULL THEN b.zip
ELSE c.zip
END as zip,
invno, descrip, qtyshp, price, extprice, b.tax, invdte
FROM artran a
LEFT JOIN arcust b ON a.custno = b.custno
LEFT JOIN soaddr c ON a.custno = c.custno
Next learning COALESCE() is a huge help to you here because it basically writes the case statement for you and returns the first non null value. So you could simply write:
SELECT DISTINCT a.custno, b.company,
COALESCE(c.address1,b.address1) as address,
COALESCE(c.city,b.city) as city,
COALESCE(c.addrstate,b.addrstate) as addrstate,
COALESCE(c.zip,b.zip) as zip,
invno, descrip, qtyshp, price, extprice, b.tax, invdte
FROM artran a
LEFT JOIN arcust b ON a.custno = b.custno
LEFT JOIN soaddr c ON a.custno = c.custno
Which will give you the soaddr column if it is not null and if it is then you will get the arcust address.
However because address data should probably be kept together meaning you should select and entire address from 1 table instead of potentially merging you should stick with your case statement but always test 1 field to determine if there is a soaddr that field should be the unique id for that table if one exists if not use another column such as Address1.
SELECT DISTINCT a.custno, b.company,
CASE WHEN c.UniqueId IS NULL THEN b.address1
ELSE c.address1
END as address,
CASE WHEN c.UniqueId IS NULL THEN b.city
ELSE c.city
END as city,
CASE WHEN c.UniqueId IS NULL THEN b.addrstate
ELSE c.addrstate
END as addrstate,
CASE WHEN c.UniqueId IS NULL THEN b.zip
ELSE c.zip
END as zip,
invno, descrip, qtyshp, price, extprice, b.tax, invdte
FROM artran a
LEFT JOIN arcust b ON a.custno = b.custno
LEFT JOIN soaddr c ON a.custno = c.custno

Related

query won't work after pivot

I'm trying to develop a query and i got something like this
SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE
WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode AS matcode,
c.LotNo AS matlot,
CASE
WHEN e.GroupName = 'CONTACT' THEN 'CONTACT'
ELSE 'Coil/Silver/Wire'
END AS GroupName,
( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty AS materialused
FROM PPRDDLV a
LEFT JOIN ICMUTTRAN b
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL
I got around 49000 records in around 2 seconds, then I wan't to pivot a column that has 2 kind of value, so I turned it to something like this
SELECT no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot
FROM (SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE
WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode AS matcode,
c.LotNo AS matlot,
CASE
WHEN e.GroupName = 'CONTACT' THEN 'CONTACT'
ELSE 'Coil/Silver/Wire'
END AS GroupName,
( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty AS materialused
FROM PPRDDLV a
LEFT JOIN ICMUTTRAN b
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL) AS a
PIVOT (Max(materialused)
FOR groupname IN ([CONTACT],
[Coil/Silver/Wire])) AS b
but the query won't complete even after 10 minutes, it won't even show a single records. beside that one, the first query before I used pivot, I put an order by a.no but when I executed it, the result only shows to record 105 but the query is still working and no more record was loaded.
can anyone help me find out what's going on?
thank you!
Here's the sample data collected from the inner query and the expected value after the query.
enter image description here
I realize that I selected "matcode" in the outer select while it shouldn't be there (still didn't work though, and note for the column "material used", I'll be using it later after the pivot is done)
Try using conditional aggregate instead of pivot.
SELECT no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot,
[CONTACT] = Max(CASE WHEN GroupName = 'CONTACT' THEN materialused END),
[Coil/Silver/Wire] = Max(CASE WHEN GroupName <> 'CONTACT' THEN materialused END)
FROM (<inner query>) AS a
GROUP BY no,
finish,
shift,
mccode,
NAME,
itemcode,
itemname,
qty,
lotno,
description,
okng,
matcode,
matlot
---IF you don't have index on filter columns then try to apply for performance
SELECT a.No,
a.Finish,
a.Shift,
a.McCode,
d.NAME,
b.ItemCode,
b.ItemName,
b.Qty,
b.LotNo,
b.Description,
CASE WHEN b.Description LIKE '%not good%' THEN 'NG'
ELSE 'OK'
END AS OKNG,
c.ItemCode,
c.LotNo,
MAX(CASE WHEN e.groupname ='CONTACT' THEN ( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty END)OVER(ORDER BY a.no) AS [CONTACT],
MAX(CASE WHEN e.groupname ='Coil/Silver/Wire' THEN ( c.Qty / ( a.Qty + a.QtyNg ) ) * b.Qty END)OVER(ORDER BY a.no) AS [Coil/Silver/Wire]
FROM PPRDDLV a WITH(NOLOCK)
LEFT JOIN ICMUTTRAN b WITH(NOLOCK)
ON a.PrdNo = b.TranNo
AND a.No = b.TranId
LEFT JOIN ICMUTTRAN c WITH(NOLOCK)
ON a.PrdNo = c.TranNo
AND a.Finish = c.DatePost
AND c.TranTypeID = 6
AND c.LotNo <> '0'
LEFT JOIN popr d WITH(NOLOCK)
ON a.OprCode = d.Code
LEFT JOIN ICITEM e
ON c.ItemId = e.id
WHERE c.qty IS NOT NULL
AND b.ItemCode IS NOT NULL

Selecting columns based on a case SQL

I'm wondering how I can return specific results depending on my first selected statement. Basically I have two IDs. CustBillToID and CustShipToID. If CustShipToID is not null I want to select that and all the records that are joined to it. If it is null default to the CustBillToID and all the results that are joined to that.
Here is my SQL that obviously doesn't work. I should mention I tried to do a sub query in the conditional, but since it returns multiple results it won't work. I am using SQL Server 2012.
SELECT CASE WHEN cp.CustShipToID IS NOT NULL
THEN
cy.CustDesc,
cy.Address1,
cy.Address2,
cy.City,
cy.State,
cy.ZIP,
cy.Phone
ELSE
c.CustDesc,
c.Address1,
c.Address2,
c.City,
c.State,
c.ZIP,
c.Phone
END
LoadID,
cp.CustPOID,
cp.POBillToRef,
cp.POShipToRef,
cp.CustBillToID,
cp.CustShipToID,
cp.ArrivalDate,
cp.LoadDate,
cp.StopNum,
cp.ConfNum,
cp.EVNum,
cp.ApptNum,
ld.CarrId,
ld.Temperature,
cr.CarrDesc
FROM [Sales].[dbo].[CustPO] AS cp
LEFT OUTER JOIN Load AS ld
ON cp.LoadID = ld.LoadID
LEFT OUTER JOIN Carrier AS cr
ON ld.CarrId = cr.CarrId
LEFT OUTER JOIN Customer AS c
ON c.CustId = cp.CustBillToID
WHERE CustPOID=5213
Any ideas?
Also my current SQL is below, I do a conditional to determine if it's set. I'd rather do it in SQL if possible.
SELECT cp.LoadID,
cp.CustPOID,
cp.POBillToRef,
cp.POShipToRef,
cp.CustBillToID,
cp.CustShipToID,
cp.ArrivalDate,
cp.LoadDate,
cp.StopNum,
cp.ConfNum,
cp.EVNum,
cp.ApptNum,
ld.CarrId,
ld.Temperature,
cr.CarrDesc,
c.CustDesc as CustBillToDesc,
c.Address1 as CustBillAddress1,
c.Address2 as CustBillAddress2,
c.City as CustBillCity,
c.State as CustBillState,
c.ZIP as CustBillZIP,
c.Phone as CustBillPhone,
cy.CustDesc as CustShipToDesc,
cy.Address1 as CustShipAddress1,
cy.Address2 as CustShipAddress2,
cy.City as CustShipCity,
cy.State as CustShipState,
cy.ZIP as CustShipZIP,
cy.Phone as CustShipPhone
FROM [Sales].[dbo].[CustPO] as cp
left outer join Load as ld
on cp.LoadID = ld.LoadID
left outer join Carrier as cr
on ld.CarrId = cr.CarrId
left outer join Customer as c
on c.CustId = cp.CustBillToID
left outer join Customer as cy
on cy.CustId = cp.CustShipToID
WHERE CustPOID=?
You need a separate case for each column:
SELECT (CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.CustDesc ELSE c.CustDesc END) as CustDesc,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.Address1 ELSE c.Address1 END) as Address1,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.Address2 ELSE c.Address2 END) as Address2,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.City ELSE c.City END) as City,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.State ELSE c.State END) as State,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.ZIP ELSE c.ZIP END) as ZIP,
(CASE WHEN cp.CustShipToID IS NOT NULL THEN cy.Phone ELSE c.Phone END) as Phone,
. . .
For this, you basically want to build a string that is your SQL and then execute the string...look # the answer to this one ::
SQL conditional SELECT
Did you try coalesce(CustShipToID,CustBillToID ) ?
...
FROM [Sales].[dbo].[CustPO] as cp
left outer join Load as ld
on cp.LoadID = ld.LoadID
left outer join Carrier as cr
on ld.CarrId = cr.CarrId
inner join Customer as c
on c.CustId = coalesce(cp.CustShipToID,cp.CustBillToID )
...

Tree Like Query On SQL Server

i have a query join 4 tables
SELECT
a.Id AS KelompokInformasi, d.Name AS Domain, d.Id AS Dimension, e.Text AS Description FROM XBRLNamespaces a
INNER JOIN Hypercubes b
ON a.XBRLView_ViewId = b.XBRLView_ViewId
INNER JOIN HypercubeDimensionItems c
ON b.XBRLHypercubeId = c.XBRLHypercube_XBRLHypercubeId
INNER JOIN Items d
ON c.XBRLItem_ItemId = d.ItemId
INNER JOIN Labels e
ON d.ItemId = e.XBRLItem_ItemId
WHERE a.Id like '%AAKX%'
the query result is
KelompokInformasi Domain Dimension Description
AAKX JWAAKT dim_JWAAKT Jangka Waktu Aset
AAKX KOKOLT dim_KOKOLT Kolektibilitas
AAKX SNOUPL dim_SNOUPL Status Operasional Usaha Pihak Lawan
AAKX is a parent from the other data in Domain, Dimension, and Description.
So, i want to change the query and in the end have an output query result like this:
KelompokInformasi Domain Dimension Description
AAKX NULL NULL NULL
NULL JWAAKT dim_JWAAKT Jangka Waktu Aset
NULL KOKOLT dim_KOKOLT Kolektibilitas
NULL SNOUPL dim_SNOUPL Status Operasional Usaha Pihak Lawan
I think you must use Group by with cube and having. Or grouping sets.
http://technet.microsoft.com/en-us/library/bb522495(v=SQL.105).aspx
SELECT
'KelompokInformasi' =
CASE
WHEN a.Id like '%AAKX%' THEN a.Id
ELSE NULL
END,
'Domain' =
CASE
WHEN a.Id like '%AAKX%' THEN NULL
ELSE d.Name
END,
'Dimension' =
CASE
WHEN a.Id like '%AAKX%' THEN NULL
ELSE d.Id
END,
'Description' =
CASE
WHEN a.Id like '%AAKX%' THEN NULL
ELSE e.Text
END,
FROM XBRLNamespaces a
INNER JOIN Hypercubes b
ON a.XBRLView_ViewId = b.XBRLView_ViewId
INNER JOIN HypercubeDimensionItems c
ON b.XBRLHypercubeId = c.XBRLHypercube_XBRLHypercubeId
INNER JOIN Items d
ON c.XBRLItem_ItemId = d.ItemId
INNER JOIN Labels e
ON d.ItemId = e.XBRLItem_ItemId
WHERE a.Id like '%AAKX%'
You can use Common table Expression(CTE),ROW_NUMBER() and Same Case statement used as above:
WITH cte AS
SELECT
a.Id AS KelompokInformasi,d.Name AS DOMAIN,d.Id AS Dimension,e.Text AS Description ,
ROW_NUMBER() OVER (PARTITION BY a.Id ORDER BY a.ID) AS COL5
FROM XBRLNamespaces a
INNER JOIN Hypercubes b
ON a.XBRLView_ViewId = b.XBRLView_ViewId
INNER JOIN HypercubeDimensionItems c
ON b.XBRLHypercubeId = c.XBRLHypercube_XBRLHypercubeId
INNER JOIN Items d
ON c.XBRLItem_ItemId = d.ItemId
INNER JOIN Labels e
ON d.ItemId = e.XBRLItem_ItemId
WHERE a.Id LIKE '%AAKX%' )
SELECT CASE
WHEN COL5 >1 THEN NULL ELSE KelompokInformasi END AS KelompokInformasi,
CASE
WHEN COL5=1 THEN NULL ELSE DOMAIN END AS DOMAIN,
CASE
WHEN COL5=1 THEN NULL ELSE Dimension END AS Dimension,
CASE
WHEN COL5=1 THEN NULL ELSE Description END AS Description
FROM cte

Why does inequality test eliminate NULL values?

After I added c.category <> 'AGILE' to the query below, the results set stopped including NULL values for c.category. How can I get rows with a NULL c.category back in my result set, without doing a UNION?
select
p.number,
p.method
,sum(p.amount) AS amount
,count(*) AS count,c.category
from payments p
inner join headers a
on p.name = a.name
inner join customer c
on c.number = p.number
and a.status = 'APPROVED'
and a.type IN ('REGULAR', 'TRANSFER', 'OTHER')
and c.category <> 'AGILE'
group by
p.payment_method
,p.cust_number
,c.u_cust_category
NULL is neither equal to nor unequal to any particular value. If you want to include NULL values, you would want something like
and( c.category <> 'AGILE'
or c.category IS NULL)
Here's one way:
AND (c.category IS NULL OR c.category <> 'AGILE')
Here's another:
AND NVL(c.category, 'foo') <> 'AGILE'
This simply works:
(c.category <> 'AGILE' OR c.category IS NULL)

comparing fields in 2 different tables using SQL

I would like to compare if the address fields in contact table are different to that of the delivery table.
SELECT contactID, addressline1
FROM contact
where contactID = '0018319'
Below is the delivery table which contains the old details.
SELECT contactID, addressline1
FROM delivery
where contactID = '0018319'
SELECT contactID, d.addressline1, c.addressline1
FROM delivery d
INNER JOIN contact c on d.contactID = c.contactID
where d.addressline1 != c.addressline1
If you want to return a flag, then you would use case in the select statement:
select contactId,
(case when d.addressline1 = c.addressline1 or d.addressline1 is null and c.addressline1 is null
then 'SAME'
else 'DIFFERENT'
end) as SameOrDifferent
from contact c join
delivery d
on c.contactId = d.contactId
where contactId = '0018319';
This is going to compare each address in the two tables.
If you want to know if all are the same, then the query is more complicated. The idea is to do a full outer join between the two table (for the given contractid) on addressline1. If all the addresslines match, then the full outer join will never produce NULL values. If any are missing (on either side), then there will be NULL values.
select coalesce(c.contactId, d.contactId) as contactId,
(case when sum(case when c.addressline1 is null or d.addressline1 is null
then 1
else 0
end) = 0
then 'SAME'
else 'DIFFERENT'
end) as SameOrDifferent
from (select c.* from contact c where c.contactId = '0018319') c full outer join
(select d.* from delivery d where d.contactId = '0018319') d
on c.addressline1 = d.addressline1 and
c.contactId = d.contactId -- not actually necessary but useful for multiple contacts
group by coalesce(c.contactId, d.contactId)