How to count all null values of right join by nesting it? - sql

SELECT COUNT(Orders.EmployeeID)
FROM Orders
WHERE (Orders.EmployeeID IS NULL)
AND (IN(SELECT Orders.EmployeeID
FROM Orders
RIGHT JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID))
GROUP BY Orders.EmplyoeeID;

You need to say us which DBMS are you using? MySQL or SQL Server? You have tagged both!
In SQL Server:
SELECT COUNT( CASE
WHEN Orders.EmployeeID IS NULL THEN 1
ELSE NULL
END
)
FROM Orders
RIGHT JOIN Employees
ON Orders.EmployeeID = Employees.EmployeeID;
If you pass a column name to the COUNT function, it wont count the null values, so in order to count the NULL values, you can use CASE to determine the NULL values and make COUNT function to count them(WHEN Orders.EmployeeID IS NULL THEN 1) and also you need to determine the non-NULL values and make make COUNT function not to count them(ELSE NULL).
Read more about COUNT here: https://learn.microsoft.com/en-us/sql/t-sql/functions/count-transact-sql?view=sql-server-2017

Related

Accounting for nulls the correct way

In my below query I want to account for and not count users with null value in distance column - which of the below is the most optimal? I am also not sure how the HAVING ifnull works but it removes any user with null in distance column or 0 as the sum which what I wanted
Having
SELECT
name,
SUM(distance) as distance_traveled
FROM users
LEFT JOIN rides
ON users.id = rides.passenger_user_id
GROUP BY name
HAVING IFNULL(SUM(distance), 0)
Coalesce
SELECT
name,
COALESCE(SUM(distance),0) as distance_traveled
FROM users
LEFT JOIN rides
ON users.id = rides.passenger_user_id
GROUP BY name
Not Null Filter
SELECT
name,
SUM(distance) as distance_traveled
FROM users
LEFT JOIN rides
ON users.id = rides.passenger_user_id
and distance is not null
GROUP BY name
Thanks
The SUM aggregate function, by default, will ignore NULL values. So, any names having a mixture of NULL and non NULL distances will only report the sum of the non NULL values. However, for the case of a name only having NULL distances, the sum would return NULL. Using COALESCE as you have done in the second version is a typical way of dealing with this:
SELECT u.name, COALESCE(SUM(r.distance), 0) AS distance_traveled
FROM users u
LEFT JOIN rides r
ON u.id = r.passenger_user_id
GROUP BY u.name;
If you want to remove any users having all NULL distances, then add the following HAVING clause:
HAVING COUNT(r.distance) = 0
If you want to filter off any users with all zero distances (i.e. either missing or present but reported as NULL), then use this HAVING clause:
HAVING SUM(r.distance) > 0

How to prioritise selection of one column value over another on join?

I have two tables, namely offers(containing columns id and user_id) and offer_maps (containing offer_id, user_id). I want to join both of the tables on offer_id, and the final selection should have user_id column populated by prioritising offer_maps' user_id column over offers' user_id column. For example, if offer_maps' user_id column is null and offers' user_id column has a value, the final user_id should have offers' user_id column. But if both are populated, then pick only offer_maps' user_id column value. How can I achieve this through sql query? Here's a sample which I wrote
select concat(offers.user_id, o.user_id) AS user_id
from offers
left join offer_maps o on offers.id::text = o.offer_id
This actually joins both the values of columns, but I need only one in case both exist.
You can use ISNULL in this case:
select ISNULL (offers.user_id, o.user_id) AS user_id
from offers
left join offer_maps o on offers.id::text = o.offer_id
--This assumes O.user_id is not nullable, but OM.user_id is:
SELECT O.id[offer_id], ISNULL(O.user_id, OM.user_id)[user_id]
FROM offers as O
LEFT JOIN offer_maps as OM
ON OM.offer_id = O.id
AND ISNULL(OM.user_id, O.user_id) = O.user_id --Join when OM.user_id is null.

Count Returning blank instead of 0

Good day everyone. Here is my code:
SELECT
'Expired Item -'+ DateName(mm,DATEADD(MM,4,AE.fld_LOAN)) as [Month]
,COUNT(PIT.fld_ID)'COUNT'
,SUM (PIT.fld_GRAM)'GRAMS'
,SUM (PH.fld_AMNT)'PRINCIPAL'
FROM #AllExpired AE
INNER JOIN Transactions.tbl_ITEM PIT
ON AE.fld_MAINID=PIT.fld_MAINID
INNER JOIN Transactions.tbl_HISTO PH
ON AE.fld_MAINID =PH.fld_MAINID
GROUP BY DATENAME(MM,(DATEADD(MM,4,AE.fld_LOAN)))
The problem I'm facing is that my Count function does not return 0 if it has no values, Sum function does not return NULL if there are no resulting values retrieved. Instead, it just outputs blank. Why is that so and how can I fix it?
Here is a screenshot of sample output.
Of course this is not what I want. I want it to output zero and null. Please help me, I do not know what's wrong. Thank you.
You cannot expect any records to be outputted when using a GROUP BY clause, when no records exist in your source.
If you want an output of 0 from the SUM and COUNT functions, then you should not use GROUP BY.
The reason is that when you have no records, the GROUP BY clause has nothing to group by, and then is not able to give you any output.
For example:
SELECT COUNT(*) FROM (SELECT 'Dummy' AS [Dummy] WHERE 1 = 0) DummyTable
will return one record with the value '0', where as:
SELECT COUNT(*) FROM (SELECT 'Dummy' AS [Dummy] WHERE 1 = 0) DummyTable
GROUP BY [Dummy]
will return no records.
I would imagine you need to change your joins from INNER to OUTER to ensure rows are returned even when there is no corresponding record in tbl_PawnItem -
SELECT
'Expired Item -'+ DateName(mm,DATEADD(MM,4,AE.fld_LoanDate)) as [Month]
,COUNT(PIT.fld_PawnItemID)'COUNT'
,SUM (PIT.fld_KaratGram)'GRAMS'
,SUM (PH.fld_PrincipalAmt)'PRINCIPAL'
FROM #AllExpired AE
LEFT JOIN Transactions.tbl_PawnItem PIT
ON AE.fld_PawnMainID=PIT.fld_PawnMainID
LEFT JOIN Transactions.tbl_PawnHisto PH
ON AE.fld_PawnMainID=PH.fld_PawnMainID
GROUP BY DATENAME(MM,(DATEADD(MM,4,AE.fld_LoanDate)))
Perhaps #AllExpired is empty, or one of the joins returns no results?
Remember inner joins need results on both sides in order to return, so because #AllExpired is empty the join returns nothing.
Change it to an OUTER join.

SQL: Including Null values with Outer Joins

Using this query, my output includes all values where COUNT is 0, but I still get the warning that Null values have been not been included. The double joins are to get the tables linked appropriately to count the number of orders, but I want to include all NULL as well, not just where COUNT is 0. What am I missing?
SELECT EmpNo, LastName, COUNT(CustomerOrder.OrderNo)
FROM Employee
LEFT OUTER JOIN Customer
ON Customer.AcctRepNo = EmpNo
LEFT OUTER JOIN CustomerOrder
ON Customer.CustNo =CustomerOrder.CustNo
GROUP BY EmpNo, LastName
ORDER BY COUNT(CustomerOrder.OrderNo) DESC, LastName
The results are fine, it is including all your values. The message it's only saying that when the column CustomerOrder.OrderNo is null, then it is not counting them (hence, the count value of zero).

get COUNT to return 0 when EXISTS() subquery is false

Given the following query:
SELECT M.year, COUNT(C.eid)
FROM Card AS C, Month AS M
WHERE EXISTS(SELECT 1 FROM Charge AS CH
WHERE CH.usingcard=C.eid AND CH.year=M.year)
GROUP BY M.year
where EXISTS is used to avoid the number of 'Charge' matching the given year/card changing the count. The pb is that I would like a resulting row for each possible 'Month' row, eg when there are no matching 'Charge', I would like to get 0 as count, while I currently get no row at all.
Without EXISTS, I could use an outer join. I could also probably use an UNION with a query returning 0 for case where NOT EXISTS().
Anyone has a smarter idea ?
This avoids the the problem of multiple Charge records:
SELECT M.year, COUNT(distinct CH.usingcard)
FROM Card AS C
CROSS JOIN Month AS M
LEFT JOIN Charge CH on CH.usingcard=C.eid AND CH.year=M.year
GROUP BY M.year
This counts how may different cards were charged in the year. Non-joining rows will have CH.usingcard of null, which won't be counted.
The NOT EXISTS is excluding zero counts: as expected
If you want zero counts, then you need the OUTER JOIN. However, your FROM clause is a CROSS JOIN so you'd get wrong counts. And you can ignore the Card table because usingcard has the same data (otherwise you wouldn't use it in your EXISTS)
It is this simple...
SELECT
M.year, COUNT(CH.usingcard)
FROM
Month AS M
LEFT JOIN
Charge AS CH On CH.year = M.year
GROUP BY
M.year
If all arguments are NULL, COALESCE returns NULL.
COALESCE(expression1,...n) is equivalent to the following CASE expression:
CASE
WHEN (expression1 IS NOT NULL) THEN expression1
WHEN (expression2 IS NOT NULL) THEN expression2
...
ELSE expressionN
END
The following example shows how COALESCE selects the data from the first column that has a nonnull value.
SELECT Name, Class, Color, ProductNumber,
COALESCE(Class, Color, ProductNumber) AS FirstNotNull
FROM Production.Product ;
You could the NULLIF function which can be used inside the count function. This function takes two parameters: if the parameters are equal, then it returns null, else it returns the value of the first parameter.
SELECT M.year, COUNT (NULLIF (CH.usingcard, NULL))
FROM Month as M left join Charge as CH
ON CH.Year = M.Year
GROUP BY M.year