Why does inequality test eliminate NULL values? - sql

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)

Related

Where clause on custom column

select c.base_id,case when c.type is not null then c.type else g.type end as type, c.function_id
from cust c
left join category cg on c.cat_id=cg.id
where c.type='privelleged'; --- where clause is not working as expected
What am I missing in the above query.The where clause is not working as expected.
I need to apply the where clause on the derived 'type' column. How do I acheive that in Oracle.
Thanks in advance
I suspect that you just want coalesce() -- in both the select and where:
select c.base_id, coalesce(c.type, g.type) as type, c.function_id
from cust c left join
category cg
on c.cat_id = cg.id
where coalesce(c.type, g.type) = 'privileged';
You can't use that derived column the way you wanted - you need to use the same CASE in WHERE as well:
select c.base_id,
case when c.type is not null then c.type
else g.type
end as type,
c.function_id
from cust c
left join category cg on c.cat_id = cg.id
where case when c.type is not null then c.type --> here
else g.type
end = 'privelleged';
Alternatively, use current query as a CTE (or a subquery) and apply filter on it:
with temp as
(select c.base_id,
case when c.type is not null then c.type
else g.type
end as type,
c.function_id
from cust c
left join category cg on c.cat_id = cg.id
)
select *
from temp
where type = 'privelleged';

Pull a separate column that matches the (min) of an aggregate function

It works well so far but I am stumped from here as I am brand new to this. This query finds the closest distance match, pairing up every item in the "FAILED" folder against everything that isn't in the "FAILED" folder.
There is a column "RouteID" in the "table p" that I want to match up with the min() aggregate.
I cannot process how to make the SELECT query simply show the associated "RouteID" column from tbl p but ultimately, I want to turn this into an update query that will SET a.Route = p.Route that is associated with the min()
Any help would be appreciated.
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
You can select them separately and then join them
SELECT c.name, c.Reference1, q.RouteID
FROM
(
SELECT a.name, a.Reference1,
MIN(round(ACOS(COS(RADIANS(90-a.lat))
*COS(RADIANS(90-p.latpoint))
+SIN(RADIANS(90-a.lat))
*SIN(RADIANS(90-p.latpoint))
*COS(RADIANS(a.lon-p.longpoint)))
*3958.756,2)) AS 'DISTANCE'
FROM tblOrder AS a WITH (NOLOCK)
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrder b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS p ON 1=1
WHERE a.CustID = 180016
AND a.RouteID = 'FAILED'
AND a.StopType = 1
AND P.RouteID <> 'FAILED'
GROUP BY
a.name, a.Reference1
) c
LEFT JOIN
(
SELECT b.lat AS latpoint, b.lon AS longpoint,
b.Sequence, b.routeid
from tblOrderRouteStops b WITH (NOLOCK)
WHERE b.CUSTID = 180016
AND b.routeID <> 'FAILED'
AND b.StopType = 1
) AS q
ON q.routeID = c.DISTANCE

Avoid NULL value in CASE SQL SERVER

How to avoid NULL values in CASE and SUM by P.Id. Problem is that i have more than one DPB.ProductTypeId in DPB table
SELECT P.[Id],
CASE
WHEN DPB.ProductTypeId = 1 THEN SUM(DPB.BonusAmount)
END AS [CasinoBonus]
FROM Player P
JOIN PlayerBonus DPB ON P.[Id] = DPB.[PlayerId]
group by P.[Id],DPB.ProductTypeId
use case when inside sum
SELECT P.[Id],
sum(CASE
WHEN DPB.ProductTypeId = 1 THEN DPB.BonusAmount
else 0
END) AS [CasinoBonus]
FROM Player P
JOIN PlayerBonus DPB ON P.[Id] = DPB.[PlayerId]
where P.[Id] is not null and DPB.[PlayerId] is not null
group by P.[Id],DPB.ProductTypeId
The case should be the argument to the sum(). You query should look like this:
SELECT P.[Id],
SUM(CASE WHEN DPB.ProductTypeId = 1 THEN DPB.BonusAmount
END) AS [CasinoBonus]
FROM Player P JOIN
PlayerBonus DPB
ON P.[Id] = DPB.[PlayerId]
GROUP BY P.[Id];
Note that you don't want DPB.ProductTypeId in the GROUP BY.
That said, you may simply want:
SELECT P.[Id],
SUM(DPB.BonusAmount) AS [CasinoBonus]
FROM Player P LEFT JOIN
PlayerBonus DPB
ON P.[Id] = DPB.[PlayerId] AND
DPB.ProductTypeId = 1
GROUP BY P.[Id];
Moving the condition to the WHERE clause removes the need for the CASE entirely. The LEFT JOIN keeps all players, even those that don't have that product type.

SQL CASE returning wrong values

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

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