Get the sum of (count(column1) + count(column2)) - sql

I have a table A:
entity_id name
------------------
1 Test1
2 Test2
3 Test3
4 Test4
5 Test5
6 Test6
I have a table B:
entity_id value1 value2
-----------------------------
1 10 20
1 15 30
2 10 25
1 9 45
3 null 1
2 45 50
3 20 null
I need to write a single query to select the entity_id and name from Table A and count the total occurrences for an entity_id of columns value1 and value2 from Table B and then the total of those column counts (null doesn't count).
So my output table would be:
entity_id name value1_count value2_count total_count
----------------------------------------------------------------------
1 Test1 3 3 6
2 Test2 1 2 3
3 Test3 1 1 2
4 Test4 0 0 0
5 Test5 0 0 0
6 Test6 0 0 0
I am having trouble summing the count of value1 and count of value2 and outputting that value in the total_count per unique entity_it.
This is the query I have so far:
SELECT DISTINCT a.entity_id, a.name
, count(b.value1) AS value1_count, count(b.value2) AS value2_count, sum(2) AS total_count
FROM a
LEFT JOIN b ON a.entity_id = b.entity_id
GROUP BY a.entity_id, a.name
I know that the sum(2) as total_count is incorrect and doesn't get me what I want.

SELECT entity_id, a.name
, COALESCE(b.v1_ct, 0) AS value1_count
, COALESCE(b.v2_ct, 0) AS value2_count
, COALESCE(b.v1_ct + b.v2_ct, 0) AS total_count
FROM a
LEFT JOIN (
SELECT entity_id, count(value1) AS v1_ct, count(value2) AS v2_ct
FROM b
GROUP BY 1
) b USING (entity_id);
db<>fiddle here
Aggregate first, join later. That's simpler and faster. See:
Query with LEFT JOIN not returning rows for count of 0
count() never produces NULL. Only the LEFT JOIN can introduce NULL values for counts in this query, so v1_ct and v2_ct are either both NULL or both NOT NULL. Hence COALESCE(v1_ct + v2_ct, 0) is ok. (Else, one NULL would nullify the other summand in the addition.)

try this :
WITH list AS
(
SELECT b.entity_id
, count(*) FILTER (WHERE b.value1 IS NOT NULL) OVER () AS value1_count
, count(*) FILTER (WHERE b.value2 IS NOT NULL) OVER () AS value2_count
FROM Table_B AS b
GROUP BY b.entity_id
)
SELECT a.entity_id, a.name
, COALESCE(l.value1_count, 0)
, COALESCE(l.value2_count,0)
, COALESCE(l.value1_count + l.value2_count, 0) AS total_count
FROM Table_A AS a
LEFT JOIN list AS l
ON a.entity_id = l.entity_id

Related

How to select data with group by and subquery calculations?

I have two tables:
list_table:
id
name
1
a
2
b
3
c
vt_table:
id
list_id
amount
direction_id
1
1
20
1
2
1
12
2
3
1
15
1
4
2
23
1
5
1
20
1
6
1
20
2
7
1
18
1
I need this result:
amount (dir_id = 1 - dir_id = 2), list_id
amount
list_id
41
1
23
2
0
3
Amount is sum of all amount fields in table vt_table where direction_id = 1 minus sum of all amount fileds in table vt_table where direction_id = 2
And I need group this calculations by list_id, and if table have no rows with list_id 3, as example, amount must be 0.
I'm trying to do it with this query:
SELECT vt.list_id
, ((SELECT COALESCE(SUM(vt.amount), 0)
FROM table_name vt
WHERE vt.direction_id = 1)
-
(SELECT COALESCE(SUM(vt.amount), 0)
FROM table_name vt
WHERE direction_id = 2)) AS result
FROM table_name vt
GROUP BY vt.list_id
But I don't know how to group it correctly and make it so that if there were no entries for some list_id, then the amount was 0 for this list_id.
I use PostgreSQL 12.
Here the examples
You can try to use OUTER JOIN with condition aggregate function with COALESCE fucntion.
Query 1:
SELECT l.id,
SUM(COALESCE(CASE WHEN vt.direction_id = 1 THEN vt.amount END,0)) -
SUM(COALESCE(CASE WHEN vt.direction_id = 2 THEN vt.amount END,0)) AS result
FROM table_name vt
RIGHT JOIN list l ON vt.list_id = l.id
GROUP BY l.id
ORDER BY l.id
Results:
| id | result |
|----|--------|
| 1 | 41 |
| 2 | 23 |
| 3 | 0 |
Try something like this, as a start:
SELECT vt.list_id
, COALESCE(SUM(CASE WHEN direction_id = 1 THEN amount END), 0)
- COALESCE(SUM(CASE WHEN direction_id = 2 THEN amount END), 0) AS result
FROM table_name vt
GROUP BY vt.list_id
;
Result using your fiddle:
list_id
result
1
41
2
23
This just misses the cases where there are no vt rows for some list.
Use an outer join to address those cases.
SELECT SUM(CASE WHEN vt.direction_id = 1 THEN vt.amount ELSE 0 END) - SUM(CASE WHEN vt.direction_id = 2 THEN vt.amount ELSE 0 END) as amount,
lt.id as list_id
FROM list_table lt
LEFT OUTER JOIN vt_table vt
ON lt.id = vt.list_id
GROUP BY lt.id
ORDER BY lt.id

using case with aggregate function with select & group by clauses

I've the below table
ID TYPE
--- ----
1 P
1 W
2 P
3 W
4 W
4 X
5 P
6 null
I need a new table to be created like the one below
ID Count of Type Code
-- -------------- -------
1 2 null
2 1 P
3 1 W
4 2 null
5 1 P
6 0 null
1st col ---> ID
2nd col ---> count of "type" for an ID
3rd col ---> if count(type) = 1 then TYPE
else null
Kindly help me in writing an ORACLE SQL query
You could use a subquery with the max function to get a value for the code and then use that in a case statement to get the value in your final query only when the count=1.
select id, cnt, case when cnt=1 then maxtype else null end as code
from
(select id, count(*) as cnt, max(type) as maxtype
from t1
group by id) t2

SQL query to group based on sum

I have a simple table with values that I want to chunk/partition into distinct groups based on the sum of those values (up to a certain limit group sum total).
e.g.,. imagine a table like the following:
Key Value
-----------
A 1
B 4
C 2
D 2
E 5
F 1
And I would like to group into sets such that no one grouping's sum will exceed some given value (say, 5).
The result would be something like:
Group Key Value
-------------------
1 A 1
B 4
--------
Total: 5
2 C 2
D 2
--------
Total: 4
3 E 5
--------
Total: 5
4 F 1
--------
Total: 1
Is such a query possible?
While I am inclined to agree with the comments that this is best done outside of SQL, here is some SQL which would seem to do roughly what you're asking:
with mytable AS (
select 'A' AS [Key], 1 AS [Value] UNION ALL
select 'B', 4 UNION ALL
select 'C', 2 UNION ALL
select 'D', 2 UNION ALL
select 'E', 5 UNION ALL
select 'F', 1
)
, Sums AS (
select T1.[Key] AS T1K
, T2.[Key] AS T2K
, (SELECT SUM([Value])
FROM mytable T3
WHERE T3.[Key] <= T2.[Key]
AND T3.[Key] >= T1.[Key]) AS TheSum
from mytable T1
inner join mytable T2
on T2.[Key] >= T1.[Key]
)
select S1.T1K AS StartKey
, S1.T2K AS EndKey
, S1.TheSum
from Sums S1
left join Sums S2
on (S1.T1K >= S2.T1K and S1.T2K <= S2.T2K)
and S2.TheSum > S1.TheSum
and S2.TheSum <= 5
where S1.TheSum <= 5
AND S2.T1K IS NULL
When I ran this code on SQL Server 2008 I got the following results:
StartKey EndKey Sum
A B 5
C D 4
E E 5
F F 1
It should be straightforward to construct the required groups from these results.
If you want to have only two members or less in each set, you can use the following query:
Select
A.[Key] as K1 ,
B.[Key] as K2 ,
isnull(A.value,0) as V1 ,
isnull(B.value,0) as V2 ,
(A.value+B.value)as Total
from Table_1 as A left join Table_1 as B
on A.value+B.value<=5 and A.[Key]<>B.[Key]
For finding sets having more members, you can continue to use joins.

How do I return the sum for this query?

I have the following tables I need to find out the sum.
Table A
ID Name
1 Jason
2 Peter
3 Ravi
Table B
ID ID_SEC
1 11
1 12
1 13
2 21
2 22
2 23
3 31
3 32
3 33
Table C
ID_SEC Value Include_Ind
11 100 Y
12 200 Y
13 300 N
21 10 Y
22 20 N
23 30 N
31 1000 N
32 2000 N
33 3000 N
Output
ID Name Total Include_Ind_count [only count when Y]
1 Jason 600 2
2 Peter 60 1
3 Ravi 6000 0
Use:
SELECT a.id,
a.name,
SUM(c.value) AS total
FROM TABLE_A a
JOIN TABLE_B b ON b.id = a.id
JOIN TABLE_C c ON c.id_sec = b.id_sec
GROUP BY a.id, a.name
The trick to counting INCLUDE_IND only when the flag is set to 'Y' is to use CASE() to test its value:
SQL> select a.id
2 , a.name
3 , sum ( c.val) as total
4 , count( case when c.include_ind = 'Y' then 1
5 else null end ) as inc_ind_cnt
6 from a
7 join b on ( b.id = a.id )
8 join c on ( c.id_sec = b.id_sec )
9 group by a.name, a.id
10 order by a.id
11 /
ID NAME TOTAL INC_IND_CNT
---------- ---------- ---------- -----------
1 Jason 600 2
2 Peter 60 1
3 Ravi 6000 0
SQL>
The ORDER BY is necessary to guarantee sort order since Oracle changed the algorithm it uses for GROUP BY operations in 10g.
You can use inner Joins and SUM for getting the result -
Assuming you tableC.Value is int field. Else you need to cast it.
SELECT tabA.id, tabA.name, SUM(tabC.value)
FROM TABLE_A tabA
INNER JOIN TABLE_B tabB ON tabB.id = tabA.id
INNER JOIN TABLE_C tabc ON tabC.id_sec = tabB.id_sec
GROUP BY tabA.id, tabA.name

access query to filter and combine count

i have two access tables
tableA
num count
1 7
2 8
3 9
4 9
5 13
6 6
tableB
num count
0 1
1 14
2 12
3 5
4 5
5 11
6 5
how can i create an access query that will ignore the numbers which have count less than 6 in any of the two tables. i.e. 0,3,4 & 6 and create a table with the rest of the numbers sorted by combined count
tableC
num count
5 24
1 21
2 20
any help appreciated
Maybe....
SELECT a.num, a.count + b.count
FROM tableA a
JOIN tableB b on b.num = a.num
WHERE a.count >= 6
AND b.count >= 6
this will include numbers which are in both A and B. To include numbers with count >= 6 that are in one table and not the other you'll have to add a Join and a "isnull" for the a.count and b.count values. ie; isnull(a.count,0) + isnull(b.count,0)
You can try something like this
SELECT DISTINCT tableA.num, [tableA].[val]+[tableB].[val] AS Expr1
FROM tableA INNER JOIN tableB ON tableA.num = tableB.num
WHERE (((tableA.val)>=6) AND ((tableB.val)>=6));
How about
SELECT x.Num, x.Count FROM (
SELECT Num, Count(*)
FROM tableA
GROUP BY Num
HAVING Count(*)>6
UNION ALL
SELECT Num, Count(*)
FROM tableB
GROUP BY Num
HAVING Count(*)>6) x
Or if count is a field, rather than a calculation:
SELECT x.Num, x.Count FROM (
SELECT Num, Count
FROM tableA
WHERE Count>6
UNION ALL
SELECT Num, Count
FROM tableB
WHERE Count>6) x