GROUP BY with COUNT condition - sql

I have a result set such as:
Code No
1 *
1 -
1 4
1
1
Now i basically want a query that has 2 columns, a count for the total amount and a count for those that dont have numbers.
Code No_Number Total
1 4 5
Im assuming this needs a group by and a count but how can i do the 2 different counts in a query like this?
This is what i had so far, but i am a bit stuck with the rest of it
SELECT CODE,NO
Sum(Case when No IN ('*', '-', '') then 1 else 0 end) as Count

I think you basically just need GROUP BY:
SELECT CODE,
SUM(Case when No IN ('*', '-', '') then 1 else 0 end) as Count,
COUNT(*) as total
FROM t
GROUP BY CODE;

Well, this took a moment :-), however here it is...I have used a CASE statement to create and populate the No_Number column; the database gives the row in the original table a value of 1 if the original table value is a number or gives it a NULL and discards it from the COUNT if not. Then when it makes the count it is only recognising values which were originally numbers and ignoring everything else..
If the result set is in a table or temp table:
SELECT Code,
COUNT(CASE WHEN [No] NOT LIKE '[0-9]' THEN 1 ELSE NULL END) AS No_Number,
COUNT(Code) AS Total
FROM <tablename>
GROUP BY Code
If the result set is the product of a previous query you can use a CTE (Common Table Expression) to arrive at the required result or you could include parts of this code in the earlier query.

Related

Count the occurrences of a given list of values in a column using a single SQL query

I would like to get the count of occurrences of a given list of values in a column using a single SQL query. The operations must be optimised for performance.
Please refer the example given below,
Sample Table name - history
code_list
5lysgj
627czl
1lqnd8
627czl
dtrtvp
627czl
esdop9
esdop9
3by104
1lqnd8
Expected Output
Need to get the count of occurrences for these given list of codes 627czl, 1lqnd8, esdop9, aol4m6 in the format given below.
code
count
627czl
3
esdop9
2
1lqnd8
2
aol4m6
0
Method I tried in show below but the count of each input is shown as a new column using this query,
SELECT
sum(case when h.code_list = 'esdop9' then 1 else 0 end) AS count_esdop9,
sum(case when h.code_list = '627czl' then 1 else 0 end) AS count_627czl,
sum(case when h.code_list = '1lqnd8' then 1 else 0 end) AS count_1lqnd8,
sum(case when h.code_list = 'aol4m6' then 1 else 0 end) AS count_aol4m6
FROM history h;
Note - The number inputs need to be given in the query in 10 also the real table has millions of records.
If i properly understand you need to get the count of occurrences for the following codes: 627czl, 1lqnd8, esdop9.
In this case you can try this one:
SELECT code_list, count(*) as count_
FROM history
WHERE code_list in ('627czl','1lqnd8','esdop9')
GROUP BY code_list
ORDER BY count_ DESC;
dbfiddle
If you need to get the count of occurrences for all codes you can run the following query:
SELECT code_list, count(*) as count_
FROM history
GROUP BY code_list
ORDER BY count_ DESC;
you can try to use GROUP BY
Something like this
SELECT code_list, COUNT(1) as 'total' ROM h GROUP by code_list order by 'total' ;

Proportion request sql

There is a table of accidents and output the share of accidents number 2 to all accidents I wrote this code, but I can not make it work:
select ((select count("ID") from "DTP" where "REASON"=2)/count("REASON"))
from "DTP"
group by "ID"
Something like this (not tested):
select id, count(case reason when 2 then 1 end)/count(*) as proportion
from your_table
-- where ... (if you need to filter, for example by date)
group by id
;
count(*) counts all the rows in a group (that is, all the rows for each separate id). The case expression returns 1 when the reason is 2 and it returns null otherwise; count counts only non-null values, so it will count the rows where the reason is 2.
You can use avg():
select id,
avg(case when reason = 2 then 1.0 else 0 end)
from "DTP"
group by "ID"
This produces the ratio for each id -- based on your sample query. If you only want one row for all the data, then:
select avg(case when reason = 2 then 1.0 else 0 end)
from "DTP";

Count column with specific condition

How can i count columns that hold particular values - but have it as a grand-total.
table data:
Code No
1 *
2 -
3 4
4
If for example i wanted to count how many rows had * and - and space
I could do
Case when No = '*'
Then COUNT(No)
when No = '-' then count(No)
when No = '' then count(No)
else 0 end as 'Count'
but this returns 4
http://sqlfiddle.com/#!9/f73409/4
I would want this to return 3
Any help would be appreciated
Use IN:
select Sum(Case when No IN ('*', '-', '') then 1 else 0 end) as Count
from Table1
See Fiddle.
Standard SQL has a particular feature for that: the filter clause that follows aggregates.
Unfortunately, it is not very widely supported (mainly PostgreSQL).
There is an easy workaround using case however:
COUNT(CASE WHEN <condition> THEN 1 END)
This works because the implied else null clause of case and because count does not count null.
More about the filter clause and ways to mimic it: http://modern-sql.com/feature/filter

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.

select result set row to columns transformation

I've a table remarks with columns id, story_id, like like can be +1, -1
I want my select query to return the following columns story_id, total, n_like, n_dislike where total = n_like + n_dislike without sub queries.
I am currently doing a group by on like and selecting like as like_t, count(like) as total which is giving me an output like
-- like_t --+ --- total --
-1 | 2
1 | 6
and returning two rows in result set. But what I want is to get 1 row where n_like is 6 and n_dislike is 2 and total is 8
First, LIKE is a reserved word in PostgreSQL, so you have to double-quote it. Maybe a better name should be picked for this column.
CREATE TABLE testbed (id int4, story_id int4, "like" int2);
INSERT INTO testbed VALUES
(1,1,'+1'),(1,1,'+1'),(1,1,'+1'),
(1,1,'+1'),(1,1,'+1'),(1,1,'+1'),
(1,1,'-1'),(1,1,'-1');
SELECT
story_id,
sum(CASE WHEN "like" > 0 THEN abs("like") ELSE 0 END) AS n_like,
sum(CASE WHEN "like" < 0 THEN abs("like") ELSE 0 END) AS n_dislike,
count(story_id) AS total
-- for cases +2 / -3 in the "like" field, use following construct instead
-- sum(abs("like")) AS total
FROM testbed
GROUP BY story_id;
I used abs("like") for cases when you'll have +2 or -3 in your "like" column.