Single use of COUNT in CASE WHEN - sql

I have a column MessageId and have to take the count of distinct MessageId and if the result is 1, then have to display count as 0 else the count value itself. If the data set is more, using distinct twice is going to be a bit more time consuming.
...
CASE
WHEN count(DISTINCT MessageId) = 1
THEN 0
ELSE count(DISTINCT MessageId)
END as Count
...
Is there anyway to use COUNT(DISTINCT) only once using a single query itself? And also don't want to use multiple queries like assigning it to a variable and then using it.

Here is one method:
COALESCE(NULLIF(COUNT(DISTINCT MessageId), 1), 0)

it seems you need below
case when sum( case when MessageId= 1 then 1 else 0 end) =1
then 0 else
count(DISTINCT MessageId) end as cnt

Related

Aggregate sub-query not producing expected results

I have two tables and there's a one to many relationship between the two. My query has a group by and I want to determine if there are any results in the 2nd table that match some criteria. I couldn't figure it out with a sub-query and tried the following code, but it's not giving you the results you expect.
CASE WHEN
(SELECT SUM(CASE WHEN a.ContentId IS NULL THEN 1 ELSE 0 END)) > 0
THEN 1
ELSE 0
END as 'HasAttachments'
Basically, I am trying to figure out if my message (which could have many attachments) has any attachments where the ContentId is null and if that count is greater than 0 then I want to return the boolean value in HasAttachments.
Any help would be great!
CASE WHEN
SUM(CASE WHEN a.ContentId IS NULL
AND a.message_id IS NOT NULL
THEN 1
ELSE 0
END) > 0
THEN 1
ELSE 0
END as HasAttachments
From your narratives it seems like your inner Case Statement is missing another condition to determine when there is actually an attachment. If you don't put in the second condition of when the AttachmentTable.message_id IS NOT NULL then you will count both messages that don't have any attachments and those messages that have attachments but no content id as the same thing. But adding the a.message_id you limit that to just the case you seem to desire from your narrative.
Here is one way I might phrase the query:
select m.*,
(case when exists (select 1 from attachments a where a.message_id = m.message_id and content_id is null
)
then 1 else 0
end) as HasAttachments
from messages m;
It is unclear why your query doesn't work, without the context of the rest of the query.

Apply where clause within count in sql

SELECT
Rooms.Building,
Count(Rooms.Room) AS TotalApartments,
Count(Rooms.Room) AS ApartmentsOccupied
FROM
Rooms
WHERE
(((Rooms.AssetType) <> 'LC'))
GROUP BY
Rooms.Building;
I want to count Rooms.Room Where Rooms.Occupied = True (ApartmentsOccupied) but when I put this clause into my sql it also applies the where to the TotalApartments column
You can move some logic into CASE statements to do conditional summarization:
SELECT
Rooms.Building,
Count(Rooms.Room) AS TotalApartments,
Sum(CASE WHEN Rooms.Occupied = True THEN 1 ELSE 0 END) AS ApartmentsOccupied
FROM
Rooms
WHERE
(((Rooms.AssetType) <> 'LC'))
GROUP BY
Rooms.Building;
I'm not sure off the top of my head, but you might need to change that count to a SUM as well:
Sum(1) AS TotalApartments
And alternately, in some sql dialects the 'True' value is 1, so you could get away with something like this for the occupied count:
Sum(Rooms.Occupied) AS ApartmentsOccupied
You can do like this
SELECT
Building,
Count(Room) AS TotalApartments,
SUM(CASE WHEN Occupied = True THEN 1 ELSE 0 END) AS ApartmentsOccupied
FROM
Rooms
WHERE
AssetType <> 'LC'
GROUP BY
Building;

Stuck on a slightly tricky query, trying to ignore multiple results based on a single field

Here is a simple database representation of what I'm stuck on:
IDNumber TimeSpent Completed
1 0 No
1 0 No
1 2 No
2 0 No
3 0 No
I'm currently querying the database as such...
"SELECT Distinct (IDNumber) AS Info FROM TestTable
ORDER BY WorkOrderNumber";
And it gives me back the results
1
2
3
Which is expected.
Now, I'd like to adjust it to where any instance of an IDNumber that have TimeSpent != 0 or Completed != No means that the IDNumber isn't grabbed at all. So for example in the database given, since TimeSpent = 2, I don't want IDNumber 1 to be returned in my query at all.
My first instinct was to jump to something like this...
"SELECT Distinct (IDNumber) AS Info FROM TestTable
WHERE TimeSpent='0' AND Completed='No'
ORDER BY WorkOrderNumber";
But obviously that wouldn't work. It would correctly ignore one of the IDNumber 1's but since two others still satisfy the WHERE clause it would still return 1.
Any pointers here?
SELECT DISTINCT IDNumber
FROM TestTable
WHERE IDNumber NOT IN
(SELECT IDNUmber FROM TestTable WHERE TimeSPent <> 0 OR Completed <> 'No')
You can do this with an aggregation, using a having clause:
select IDNumber
from TestTable
group by IDNumber
having sum(case when TimeSpent = 0 then 1 else 0 end) = 0 and
sum(case when Completed = 'No' then 1 else 0 end) = 0
The having clause is counting the number of rows that meet each condition. The = 0 is simply saying that there are no matches.
I prefer the aggregation method because it is more flexible in terms of the conditions that you can set on the groups.

How to count the rows which contains non zero values in sql

SELECT round(COUNT(dmd_1wk),2) AS NBR_ITEMS_1WK
FROM table;
Field dmd_1wk has so many zeros in it. How do I Count the non zero values?
It sounds like you just need to add a WHERE clause:
SELECT
round(COUNT(dmd_1wk),2) AS NBR_ITEMS_1WK
FROM table
WHERE dmd_1wk <> 0;
If you want the count of both non-zero and zero values, then you can use something like:
SELECT
round(COUNT(case when dmd_1wk <> 0 then dmd_1wk end),2) AS NBR_ITEMS_1WK_NonZero,
round(COUNT(case when dmd_1wk = 0 then dmd_1wk end),2) AS NBR_ITEMS_1WK_Zero
FROM table;
Method 1: Case Statement. This may be useful if you need to continue to process all rows (which a where clause would prevent).
SELECT count(case when dmd_1wk = 0 then 0 else 1 end) as NonZeroCount FROM MyTable
Method 2: Where Clause.
SELECT
count(1) as NonZeroCount
FROM
MyTable
WHERE
dmd_1wk <> 0
I'd like to offer another solution using NULLIF since COUNT won't count NULL values:
SELECT round(COUNT(NULLIF(dmd_1wk,0)),2) AS NBR_ITEMS_1WK
FROM table;
And here is the Fiddle.
Good luck.
Methinks bluefeets answer is probably what you are really looking for, as it sounds like you just want to count non-zeros; but this will get you a count of zero and non-zero items if that's not the case:
SELECT
ROUND(SUM(CASE NVL(dmd_1wk, 0) = 0 THEN 1 ELSE 0 END), 2) AS "Zeros",
ROUND(SUM(CASE NVL(dmd_1wk, 0) != 0 THEN 1 ELSE 0 END), 2) AS "NonZeros"
FROM table
Although there is no point in rounding a whole number, I've included your original ROUNDs as I'm guessing you're using it for formatting, but you might want to use:
TO_CHAR(SUM(...), '999.00')
as that's the intended function for formatting numbers.
You can filter them.
SELECT round(COUNT(dmd_1wk),2) AS NBR_ITEMS_1WK
FROM table
WHERE dmd_1wk <> 0;

aggregations in case statement

I am trying to do aggregations in case statement. I found 2 ways to do it. Can anyone say what the difference between the 2 is?
(CASE WHEN Event = 5 THEN count(*) ELSE 0 END ) Follow_Count
GROUP BY Event;
SUM(CASE Event WHEN 5 THEN 1 ELSE 0 END) AS Follow_Count
Your case 1 will produce a row for each event in the table (from your group by). Your case 2 will just return 1 row.
Is there a reason that you wouldn't just write:
select count(*)
from my_table
where event = 5;
Better would be:
count(CASE Event WHEN 5 THEN 1 END) AS Follow_Count
Because
1) for count used own standart counter,
2) "else" not need (count don't count nulls)
Regards,
Sayan M.
There is no significant difference. You can decide for you which is better by comparing their execution plans.