SQL left join with 2 or more count group - sql

My table
ID catone cattwo
100 2 1
100 3 1
200 1 2
expect result (count not sum)
ID totalcat1 totalcat2
100 2 2
200 1 1
My query
select COUNT(*) as totalcat1, catone
from Table1
group by cat1
left join
select COUNT(*) as totalcat2, cattwo
from Table1
group by cattwo
Try to have both count columns catone and cattwo
Not sure how to correct it. Thank you

A simple group-by should do it
select ID, COUNT(catone) as totalcat1, COUNT(cattwo) as totalcat2
from Table1
group by ID;
Note that this simply counts the number of values that are not NULL. If your original data was this...
ID catone cattwo
100 2 1
100 3 1
100 4 NULL
... then the result would be
ID totalcat1 totalcat2
100 3 2
If you want to count the distinct values - so totalcat2 would be 1 (as only 1 value exists in that column, although it's there twice) you could use
select ID, COUNT(DISTINCT catone) as totalcat1, COUNT(DISTINCT cattwo) as totalcat2
from Table1
group by ID;
which would return totalcat1 = 3 and totalcat2 = 1.
Here's a db<>fiddle with the two options.
Here's a second db<>fiddle on request of OP with ID 200.

Related

I need a 3 table join

This is my parent table acc_detial -
ACC_DETIAL example -
acc_id
1
2
3
Now i have 3 tables:
ORDER
EMAIL
REPORT
Each table contains 100 rows and acc_id are ForeignKey from ACC_DETIAL.
In ORDER table I have a columns ACC_ID and QUANTITY. I want the count of ACC_ID and sum of QUANTITY.
ORDER table example:
acc_id
quantity
date
1
2
2022/01/22
2
5
2022/01/23
1
10
2022/01/25
3
1
2022/01/25
In EMAIL table I have a column name ACC_ID and I want count of ACC_ID.
EMAIL table example:
acc_id
mail
date
1
5
2022/01/22
2
10
2022/01/22
1
7
2022/01/23
1
7
2022/01/24
2
10
2022/01/25
In REPORT table I have a columns ACC_ID and TYPE and I want the count of ACC_ID and TYPE. Note that TYPE column has only two, possible values:
postive
negative
I want count of each, i.e. count of postive and count of negative in TYPE column.
REPORT table example:
acc_id
type
date
1
positive
2022/01/22
2
negative
2022/01/22
1
negative
2022/01/23
2
postitive
2022/01/26
2
postitive
2022/01/27
I need to take this in a single i need answer as raw query or sqlalchemy. Is it possible or not? Do I need to write separate query to get each table result ?
Result -
result based on above examplec -
acc_id
total_Order_acc_id
total_Order_quantity
total_Email_acc_id
total_Report_acc_id
total_postitive_report
total_negative_report
1
2
12
3
2
1
1
2
1
5
2
3
2
1
3
1
1
Null
Null
Null
Null
You need to aggregate then join as the following:
SELECT ADL.acc_id,
ORD.ord_cnt AS total_Order_acc_id,
ORD.tot_quantity AS total_Order_quantity,
EML.eml_cnt AS total_Email_acc_id,
RPT.rpt_cnt AS total_Report_acc_id,
RPT.pcnt AS total_postitive_report,
RPT.ncnt AS total_negative_report
FROM ACC_DETIAL ADL LEFT JOIN
(
SELECT acc_id,
SUM(quantity) AS tot_quantity,
COUNT(*) AS ord_cnt
FROM ORDERS
GROUP BY acc_id
) ORD
ON ADL.acc_id = ORD.acc_id
LEFT JOIN
(
SELECT acc_id, COUNT(*) AS eml_cnt
FROM EMAIL
GROUP BY acc_id
) EML
ON ADL.acc_id = EML.acc_id
LEFT JOIN
(
SELECT acc_id,
COUNT(*) AS rpt_cnt,
COUNT(*) FILTER (WHERE type='positive') AS pcnt,
COUNT(*) FILTER (WHERE type='negative') AS ncnt
FROM REPORT
GROUP BY acc_id
) RPT
ON ADL.acc_id = RPT.acc_id
See demo
Sample :
Select
`order`.`acc_id`,
report_email_select.`type`,
report_email_select.report_count,
report_email_select.email_count,
SUM(`quantity`) as quantity_sum
FROM
`order`
Left JOIN(
Select
report_select.`acc_id`,
report_select.`type`,
report_select.report_count,
COUNT(*) as email_count
from
(
SELECT
report.`acc_id`,
report.`type`,
COUNT(*) as report_count
FROM
`report`
WHERE
1
GROUP BY
report.`acc_id`,
report.`type`
) AS report_select
INNER JOIN email ON email.acc_id = report_select.acc_id
GROUP BY
report_select.`acc_id`,
report_select.`type`
) AS report_email_select ON `order`.acc_id = report_email_select.acc_id
GROUP BY
`order`.`acc_id`,
report_email_select.`type`;

SUM a column in SQL, based on DISTINCT values in another column, GROUP BY a third column

I'd appreciate some help on the following SQL problem:
I have a table of 3 columns:
ID Group Value
1 1 5
1 1 5
1 2 10
1 2 10
1 3 20
2 1 5
2 1 5
2 1 5
2 2 10
2 2 10
3 1 5
3 2 10
3 2 10
3 2 10
3 4 50
I need to group by ID, and I would like to SUM the values based on DISTINCT values in Group. So the value for a group is only accounted for once even though it may appear multiple for times for a particular ID.
So for IDs 1, 2 and 3, it should return 35, 15 and 65, respectively.
ID SUM
1 35
2 15
3 65
Note that each Group doesn't necessarily have a unique value
Thanks
the CTE will remove all duplicates, so if there a sdiffrenet values for ID and Group, it will be counted.
The next SELECT wil "GROUP By" ID
For Pstgres you would get
WITH CTE as
(SELECT DISTINCT "ID", "Group", "Value" FROM tablA
)
SELECT "ID", SUM("Value") FROM CTE GROUP BY "ID"
ORDER BY "ID"
ID | sum
-: | --:
1 | 35
2 | 15
3 | 65
db<>fiddle here
Given what we know at the moment this is what I'm thinking...
The CTE/Inline view eliminate duplicates before the sum occurs.
WITH CTE AS (SELECT DISTINCT ID, Group, Value FROM TableName)
SELECT ID, Sum(Value)
FROM CTE
GROUP BY ID
or
SELECT ID, Sum(Value)
FROM (SELECT DISTINCT * FROM TableName) CTE
GROUP BY ID

postgreSQL - fill in blank date rows per ID

I have a table which looks like this:
ID
money_earned
days_since_start
1
1000
1
1
2000
2
1
3000
4
1
2000
5
2
1000
1
2
100
3
I want that rows, without a days_since_start (which means that the money_earned column was empty that day) - will include all the days PER ID, and fill the money_earned with last known value, so it to look like this:
ID
money_earned
days_since_start
1
1000
1
1
2000
2
1
2000
3
1
3000
4
1
2000
5
2
1000
1
2
1000
2
2
100
3
I have tried to look up for something like that, but I don't even know what function does that...
thank you!
You can try to use CTE RECURSIVE with OUTER JOIN and LAG window function to make it.
WITH RECURSIVE CTE
AS
(
SELECT ID,MIN(days_since_start) min_num,MAX(days_since_start) max_num
FROM T
GROUP BY ID
UNION ALL
SELECT ID,min_num+1,max_num
FROM CTE
WHERE min_num+1 <= max_num
)
SELECT c.ID,
CASE WHEN t1.ID IS NULL THEN LAG(money_earned) OVER(PARTITION BY c.ID ORDER BY c.min_num) ELSE money_earned END,
c.min_num days_since_start
FROM CTE c
LEFT JOIN T t1
ON c.min_num = t1.days_since_start
AND c.ID = t1.ID
ORDER BY c.ID
sqlfiddle

Efficient way to count members of same group

Lets say that I have a dataset of people who are members of groups:
Group ID | Person ID
1 1
2 1
2 2
3 1
3 3
For each person, I want to count the number of distinct people who are in at least one of the same groups (including themselves):
Person ID | Distinct Co-Members
1 3
2 2
3 2
Is there a more efficient way to do this count other than joining the above dataset on itself with a key of the Group ID?
I think you need a self-join and group by:
select t1.personid, count(distinct t2.personid)
from t t1 left join
t t2
on t1.groupid = t2.groupid
group by t1.personid;
Here is a db<>fiddle.
Using nunique
df.merge(df,on='GroupID').groupby('PersonID_x')['PersonID_y'].nunique().reset_index()
Out[170]:
PersonID_x PersonID_y
0 1 3
1 2 2
2 3 2

find duplicate from combination of rows

I have table as below :-
SampleId1 SampleId2
1 2
1 2
2 2
3 2
1 4
2 4
2 4
3 5
I want to find duplicate combination
Eg. SampleId2 has duplicate value of SampleId1 on first two rows
Expected Result :-
SampleId1 SampleId2
1 2
2 4
I tried :-
SELECT
    SampleId1 , SampleId2, COUNT(*)
FROM
    tablename
GROUP BY
    SampleId1 , SampleId2
HAVING 
    COUNT(*) > 1
But this query is not giving me results as expected.
You just want to remove the count in your query, so you can try with below one.
SELECT
SampleId1 , SampleId2
FROM
Test_group
GROUP BY
SampleId1 , SampleId2
HAVING
COUNT(1) > 1;
I think you just don't want to project count result in your selection other wise your expected result and your query all the things 100% correct just remove count(*) from select
SELECT
SampleId1 , SampleId2
FROM
t
GROUP BY
SampleId1 , SampleId2
HAVING
COUNT(*) > 1
SampleId1 SampleId2
1 2
2 4
you want to get duplicated rows and this is the solution
SELECT a.*
FROM docs a
JOIN (
SELECT SampleId1, SampleId2, COUNT(*)
FROM docs
GROUP BY SampleId1, SampleId2
HAVING count(*) > 1
) b
ON a.SampleId1 = b.SampleId1
AND a.SampleId2 = b.SampleId2
Group BY SampleId1
ORDER BY a.SampleId2
see the result here