Aggregate to count values equal to a constant - sql

In SQL there is an expressive way to count how many values differ from 'x':
SELECT COUNT(NULLIF(col, 'x')) FROM table
I find it less elegant to count values equal to 'x':
SELECT COUNT(*) - COUNT(NULLIF(col, 'x')) FROM table
SELECT SUM(CASE WHEN col = 'x' THEN 1 ELSE 0 END) FROM table
[oracle] SELECT COUNT(DECODE(col,'x','x',NULL)) FROM table
Is there a more elegant way to do that?

SELECT
COUNT(CASE WHEN col='x' THEN 1 END) AS XCount,
COUNT(CASE WHEN col='y' THEN 1 END) AS YCount,
COUNT(CASE WHEN col='z' THEN 1 END) AS ZCount
FROM table

taste is a quite personal thing, I like to use this syntax in Oracle:
select sum(decode(text,'x',0,1))
from table

The straightforward way is to do the filtration in the WHERE clause:
SELECT COUNT(*) FROM table WHERE col = 'x'
EDIT:
If you cannot use the where clause (because you are performing several counts in the same SELECT), then I think the ways you suggested yourself are the most elegant ones.
My personal preference would be the SUM(CASE WHEN....

Related

Counting Booleans for Distinct and Non Distinct ID numbers

I have a simple table that looks like the following PNG file from the following join:
SELECT *
FROM tableA A
JOIN tableB B ON B.Main_SPACE_ID = A.Main_SPACE_ID
Table A contains Guest_ON and User_Controls (last 2 columns) and Table B contains Trigger_ON and DOCX_ON.
Issue:
What I am trying to do is count all the True's for each tableB.Subspace_ID and the DISTINCT trues for tableA.Main_SPACE_ID.
The problem is that subspace_ID from table B lives within the main_space_id from table A and therefore creates a situation where I am double counting.
I only want to count the trues for a distinct Main_space ID
Current Data Model
Desired Output:
From the above screenshot, I am trying to get a count of true values without double counting in the case for tableA_MAIN_SPACE_ID.
As you can see, each row is counted for true values as it relates to the subspace_ID (table B) for totals of 12 and 8 (1 if True, 0 if False) and for tableA, I am only counting distinct values so we only count Trues for a single MainspaceID and avoid recounting them.
If someone can advise on how to get this output from my current data model that would be very helpful!
My attempt as follows double counts trues for the Main space ID column..
SELECT
count(CASE WHEN B.TRIGGER_ON THEN 1 END) as TRIGGER_ON,
count(CASE WHEN B.DOCX_ON THEN 1 END) as DOCX_ON,
count(CASE WHEN A.GUEST_ON THEN 1 END) as SPRINTS,
count(CASE WHEN A.USER_CONTROLS THEN 1 END) as SPRINTS
FROM DataModel
What I am trying to do is count all the True's for each tableB.Subspace_ID and the DISTINCT trues for tableA.Main_SPACE_ID.
You can use conditional aggregation. In Snowflake, you can use the convenient COUNT_IF() for the first two columns. However, for the second two, you need COUNT(DISTINCT) with conditional logic:
SELECT COUNT_IF( B.Trigger_on ) as Trigger_On,
COUNT_IF( B. DOCX_ON ) as DOCX_ON,
COUNT(DISTINCT CASE WHEN A.GUEST_ON THEN A.Main_SPACE_ID END) as GUEST_ON,
COUNT(DISTINCT CASE WHEN A. USER_CONTROLS THEN A.Main_SPACE_ID END) as USER_CONTROLS
FROM tableA A JOIN
tableB B
ON B.Main_SPACE_ID = A.Main_SPACE_ID;
Mabye:
SELECT
COUNT(CASE WHEN B.TRIGGER_ON THEN 1 END) AS TRIGGER_ON,
COUNT(CASE WHEN B.DOCX_ON THEN 1 END) AS DOCX_ON,
(SELECT COUNT(*) FROM (SELECT DISTINCT A.MAIN_SPACE_ID, A.GUEST_ON FROM DataModel WHERE A.GUEST_ON = TRUE) A) AS GUEST_ON
(SELECT COUNT(*) FROM (SELECT DISTINCT A.USER_CONTROLS, A.GUEST_ON FROM DataModel WHERE A.USER_CONTROLS = TRUE) A) AS USER_CONTROLS
FROM DataModel

sql group by satisfying multiple conditions within the group

I have a table like below:
I want to select the group which has RELB_CD =9093 and INFO_SRC_CD with 7784. Both conditions should be present in the group. In the table below my output should be the group with id=139993690.
You can use aggregation with having:
select id
from t
group by id
having sum(case when relb_cd = 9093 then 1 else 0 end) > 0 and
sum(case when info_src_cde = 7784 then 1 else 0 end) > 0
hey use this code hope this will help you.
you have to ignore the date column because that one is not allowing to group
select id,fisc_ind, sum(sls_amt),relb_cd,info_scop,info_src_cd from yourtable group by id,fisc_ind,relb_cd,info_scop,info_src_cd
Another working answer. If your data are large, you could compare both GL's and this working answer and see which runs faster for you. I honestly don't know which is faster. This was slightly faster with a very short set of data.
select id
from table1
where relb_cd = 9093
intersect
select id
from table1
where info_src_cd = 7784

How do I count distinct to exclude a value?

Below is the different scales in a POS system. I am trying to count the number of distinct scales that are not 'MANUAL WT'.
This is what I have, but it is returning 2 and not 6.
count (distinct (case when d.SCALE_IN_ID != 'MANUAL WT' then 1 else 0 end)) as Num_Scale
Consider:
select count(distinct case when scale_in_id <> 'MANUAL WT' then scale_in_id end) cnt
from mytable
The problem with your original query is that the case expression turns values to either 0 and 1, and then the aggregate function computes how many distinct values are returned: since values are all 0s or 1s, there are only two distinct values (or one in edge cases): hence the result that you are getting.
A simple WHERE clause will do:
select count(distinct scale_in_id) Num_Scale
from tablename
where scale_in_id <> 'MANUAL WT'

SQL, return select results with different where clauses

I have table whose column is just the length of a session and I would like to return the number of session that have zero length and the number of sessions that have length greater than zero.
I can do that with two separate commands
select count(session_length) from my_table where session_length=0
select count(session_length) from my_table where session_length>0
But I would like to see the results combined in one table
You can do it with one query using conditional aggregation.
select
count(case when session_length = 0 then 1 end),
count(case when session_length > 0 then 1 end)
from my_table
select 1 as QryNo, count(session_length) as SessLen
from my_table
where session_length=0
union
select 2 as QryNo, count(session_length) as SessLen
from my_table
where session_length>0
or
select
case
when session_length = 0 then 1
else 2
end as QryNo,
count(session_length) as SessLen
from my_table
This may be too simple so apologies if I have misread your query but Can you use
select count(session_length) from my_table where session_length >= 0
Again, Apologies if this is not what you're looking for.

Count of two types of values in same field in MS-Access

I have this table customerDetail, in which there's a field c_type, in which "a" represents "active" and "d" represents "not-active". Now I have to find the count of both of them in same query.
I used these but no result.
SELECT Count(c_type) AS Active, Count(c_type) AS Not_Active
FROM customerDetail
WHERE c_type="a" OR c_type="d"
of course I know it obviously looks dirty, but I have also tried this, but this didn't worked either-
SELECT
Count(customerDetail.c_type) AS Active,
Count(customerDetail_1.c_type) AS Not_Active
FROM customerDetail INNER JOIN customerDetail AS customerDetail_1
ON customerDetail.Id=customerDetail_1.Id
WHERE (customerDetail.c_type="a") AND (customerDetail_1.c_type="d")
But again it wasn't helpful either, so can anyone please tell me how am I supposed to know the count of both active and non-active in same query?
select c_type, count(*)
from customer_detail
group by c_type
SELECT
SUM(IIF(c_type = "a", 1, 0)) AS Active,
SUM(IIF(c_type = "d", 1, 0)) AS Not_Active,
FROM customerDetail
WHERE c_type IN ("a", "d")
That was for MS Access.
Somehow I missed the tsql tag when first saw this question. In Transact-SQL you can employ a CASE construct, which can be said of as a more powerful equivalent of IIF in Access:
SELECT
SUM(CASE c_type WHEN 'a' THEN 1 ELSE 0 END) AS Active,
SUM(CASE c_type WHEN 'd' THEN 1 ELSE 0 END) AS Not_Active,
FROM customerDetail
WHERE c_type IN ('a', 'd')
Actually, in T-SQL I would use COUNT instead of SUM, like this:
SELECT
COUNT(CASE c_type WHEN 'a' THEN 1 END) AS Active,
COUNT(CASE c_type WHEN 'd' THEN 1 END) AS Not_Active,
FROM customerDetail
WHERE c_type IN ('a', 'd')
Here 1 in each CASE expression can be replaced by anything as long as it is not NULL (NULLs are not counted). If the ELSE part is omitted, like in the query above, ELSE NULL is implied.
The challenge here is your requirement, "in the same query".
It would be easy to create separate queries.
qryActive:
SELECT Count(*) AS Active
FROM customerDetail
WHERE c_type="a"
qryInactive:
SELECT Count(*) AS Not_Active
FROM customerDetail
WHERE c_type="d"
If you need it all in one, you can incorporate them as subqueries.
SELECT a.Active, i.Not_Active
FROM
(SELECT Count(*) AS Active
FROM customerDetail
WHERE c_type="a") AS a,
(SELECT Count(*) AS Not_Active
FROM customerDetail
WHERE c_type="d") AS i
With no JOIN or WHERE condition, you will get a "cross join" (Cartesian product) of the two subqueries. But, since each subquery produces only one row, the composite will consist of only one row.