Coalesce not evaluating second argument? - sql

I am trying to run the following query:
SELECT COALESCE(count(percent_cov), 0)
FROM sample_cov
WHERE target = 542
GROUP BY percent_cov
HAVING percent_cov < 10
Basically, I want to show the number of times this statistic was < 10, and return 0 rather than null if the count was 0. If the count is >0 I get the number I want as the result, however if the count is 0 I still get a null returned. (Same thing if I set the second argument to coalesce as a positive number). What am I doing wrong?

I rewrote your query the way I think you want it:
SELECT count(*) AS ct
FROM sample_cov
WHERE target = 542
AND percent_cov < 10;
count() returns 0 When no matching rows (or non-null values in the column) are found. No need for coalesce(). I quote the manual on this:
It should be noted that except for count, these functions return a
null value when no rows are selected.
Bold emphasis mine. If you want to return a different value when count() comes back with 0, use a CASE statement.
Also, it's no use to write count(percent_cov) while you have WHERE percent_cov < 10. Only non-null values qualify, count(*) yields the same result slightly faster and simpler in this case.
You don't need a GROUP BY clause as you don't group by anything, you are aggregating over the whole table.
You could GROUP BY target, but this would be a different query:
SELECT target, count(*)
FROM sample_cov
WHERE percent_cov < 10
GROUP BY target;
You would need to spell out the expression in the HAVING clause again. Output column names are visible in ORDER BY and GROUP BY clauses, not in WHERE or HAVING.

Related

SQL count show 0 if no rows including where condition

I'm doing a COUNT but cannot get the value 0 when there are no rows in the result.
If I remove the where condition:
AND documentstats.OPENINGDATE >= '2021-01-01T00: 00: 00.000'
it works fine and I get the value 0 when there are no rows in the result.
I am looking for an option to return value 0 in the NumberOfViews column when no rows are found in my count.
Can anyone help me?
SELECT
customertodocument.DocId,
COUNT (documentstats.DocId) AS NumberOfViews
FROM
customertodocument
LEFT JOIN
documentstats ON customertodocument.DocId = documentstats.DocId
AND customertodocument.customerId = documentstats.customerId
WHERE
customertodocument.customerId = '1111'
AND documentstats.openingdate >= '2021-01-01T00:00:00.000'
GROUP BY
customertodocument.DocId
ORDER BY
NumberOfViews ASC
The second condition in the WHERE clause is filtering out all non-matches. Because you have an explicit GROUP BY, the query will return no rows if the FROM clause has no rows.
If you want counts of 0, then move the condition to the ON clause of the LEFT JOIN. Note: Conditions on the second table go in the ON clause.
The query should look like:
SELECT cd.DocId, COUNT(ds.DocId) AS NumberOfViews
FROM customertodocument cd LEFT JOIN
documentstats ds
ON cd.DocId = ds.DocId AND
cd.customerId = ds.customerId AND
ds.openingdate >= '2021-01-01'
WHERE ds.customerId = 1111
GROUP BY cd.DocId
ORDER BY NumberOfViews ASC;
Notes:
Table aliases make the query easier to write and to read.
customerId looks like a number. If it is, then the comparison should be to a number. If the id is really a string, put the single quotes back in.
You have a date constant. There is no need to include the time. No real harm, except it clutters the query.
My guess is that there are no records in the data that meet both of the conditions. You are grouping by customertodocument.DocId, but if no values of customertodocument.DocID exist after filtering with the WHERE clause, the aggregation will have nothing to group by and you'll get no results. You can test this by running the following query:
SELECT *
FROM customertodocument
LEFT JOIN documentstats on customertodocument.DocId = documentstats.DocId and customertodocument.customerId = documentstats.customerId
WHERE customertodocument.customerId = '1111' AND documentstats.openingdate >= '2021-01-01T00:00:00.000'
your WHERE condition returns nothing so you are not getting any record. Count alone in select clause can give you 0 but you have one column and then count so you are not getting any record
What value you are expecting in the customertodocument.DocId if no matching record found.
You can get the 0 count if you remove the customertodocument.DocId from select clause keeping only count in select clause and removing the GROUP BY clause

How to get 0 if no row found from sql query in sql server

I am getting blank value with this query from sql server
SELECT TOP 1 Amount from PaymentDetails WHERE Id = '5678'
it has no row,that is why its returning blank,So I want if no row then it should return 0
I already tried with COALESCE ,but its not working
how to solve this?
You are selecting an arbitrary amount, so one method is aggregation:
SELECT COALESCE(MAX(Amount), 0)
FROM PaymentDetails
WHERE Id = '5678';
Note that if id is a number, then don't use single quotes for the comparison.
To be honest, I would expect SUM() to be more useful than an arbitrary value:
SELECT COALESCE(SUM(Amount), 0)
FROM PaymentDetails
WHERE Id = '5678';
You can wrap the subquery in an ISNULL:
SELECT ISNULL((SELECT TOP 1 Amount from PaymentDetails WHERE Id = '5678' ORDER BY ????),0) AS Amount;
Don't forget to add a column (or columns) to your ORDER BY as otherwise you will get inconsistent results when more than one row has the same value for Id. If Id is unique, however, then remove both the TOP and ORDER BY as they aren't needed.
You should never, however, use TOP without an ORDER BY unless you are "happy" with inconsistent results.

Specifying a column value in an aggregate function vs using a WHERE clause

I have a database people that looks like this:
I wanted to count the occurrences of state='CA'.
My first attempt was:
SELECT COUNT(state='CA')
FROM people
;
this returned 1 row with a value of 1000. So I thought that there were 1000 people from CA in the database.
This turns out to be incorrect. I know that they are 127, which I can verify with the query
SELECT COUNT(*)
FROM people
WHERE state='CA'
;
which returns 1 row with a value of 127.
I understand how the second query works. However, I do not understand what is wrong with the first one. What is it returning?
If you want to see what's going on, run the query:
select state='CA' from people;
You will see that you will get one result for each row in people, with the value 0 or 1 (or True/False). What you've selected is whether state='CA' for each row, and there will be just as many of those results as there are rows.
You can't constrain a COUNT statement within the statement, you have to do that via the WHERE clause as in your second example.
count is not a sum .. your first query is improper because don't return the number of the rows true .. but the total numbers of not null rows true or false
if you want a filter count you must use a where condition (as your second query) otherwise you must use an if or a a select case inside the sum() function eg:
Select sum(case
when state='CA' then 1 else 0
end) as my_result from People;
or if you want count .. use null and not 0min count
Select count(case
when state='CA' then 1 else null
end) as my_result from People;
Try this-:
Select count(case when state='CA' then 1 else null end) as xyz from People;
1st query will work if you use case when in side count,
like below query will returned count of CA
SELECT sum( case when state='CA' then 1 else 0 end)
FROM people
In first query it is assigning the value 'CA' to the column state for all 1000 rows instead of filtering the values. That is what SELECT does. SELECT does not filter the number of returning rows, it modifies the data.
Whereas in WHERE clause the rows are being filtered first then the SELECT clause runs the COUNT function.
There is a sequence for running the query. It starts from FROM then WHERE, GROUP BY, ORDER BY at the end SELECT will run.
To answer the actual question - why do you get 1000? I'm guessing that there are 1000 rows in your database, or at least 1000 where state is not null. Count will return the number of rows where the thing inside the () is not null and as one of your comments says, the part inside your () will return either true or false, neither of which is null, so will count them all. Your second example is of course the right way to do it.

Same return with and without the SUM operator PostgreSQL

I'm using PostgreSQL 10 and trying to run this query. I started with a CTE which I am referencing as 'query.'
SELECT
ROW_NUMBER()OVER() AS my_new_id,
query.geom AS geom,
query.pop AS pop,
query.name,
query.distance AS dist,
query.amenity_size,
((amenity_size)/(distance)^2) AS attract_score,
SUM((amenity_size)/(distance)^2) AS tot_attract_score,
((amenity_size)/(distance)^2) / SUM((amenity_size)/(distance)^2) as marketshare
INTO table_mktshare
FROM query
WHERE
distance > 0
GROUP BY
query.name,
query.amenity_size,
query.geom,
query.pop,
query.distance
The query runs but the problem lies in the 'markeshare' column. It returns the same answer with or without the SUM operator and returns one, which appears to make both the attract_score and the tot_attract_score the same. Why is the SUM operator read the same as the expression above it?
This is occurring specifically because each combination of columns in the group by clause uniquely identifies one row in the table. I don't know if this is intentional, but more normally, one would expect something like this:
SELECT ROW_NUMBER() OVER() AS my_new_id,
query.geom AS geom, query.pop AS pop, query.name,
SUM((amenity_size)/(distance)^2) AS tot_attract_score,
INTO table_mktshare
FROM query
WHERE distance > 0
GROUP BY query.name, query.geom, query.pop;
This is not your intention, but it does give a flavor of what's expected.

COUNT(column) returns COUNT(*)

I using this website to practice SQL. I've got this query:
SELECT DISTINCT maker
FROM Product
GROUP BY maker
HAVING COUNT(type) = 1
AND COUNT(model) > 1
For some reason both count aggregates return the same value--as if they were COUNT(*)--but this isn't what I'm expecting. Please explain why and, if it's not too much trouble, what the correct approach is.
Your having clause is:
HAVING COUNT(type) = 1 AND COUNT(model) > 1
Each component is counting the number of non-NULL rows with a value in that column. So, if type contained 200 NULLs and 100 '1's, the value would be 100. Count(*), in this case, would return the number of rows, or 300.
Perhaps you want to count the number of distinct values in each column. In that case, you can use:
HAVING COUNT(DISTINCT type) = 1 AND COUNT(DISTINCT model) > 1
In practice, though, COUNT(DISTINCT) usually uses more resources than other aggregation functions. The following does the same thing and often performs better:
HAVING min(type) = max(type) and min(model) < max(model)
Count() aggregate function, counts the number of records of the table you are query. (Product Table)
There is no difference that which column you give it as input.
It will return the same output as you said.
And it's completely normal.