SQL join sum groupby where - sql

I have following two tables:
fiddle
As a result I need a list of 'name' from tab1, where the sum of 'dur' is 10 or bigger. The connection between the two table is the 'number' from tab1 which can be found in column 'xxx' or 'yyy' from tab2.
So the expected output should be: Jack, Anna
Because the sum of 'dur' for Jack(1234) is 10 and the sum of 'dur' for Anna(7582) is 12.
So far I know how to get the sum based on one column XXX:
SELECT tab1.name FROM tab1
INNER JOIN (
SELECT xxx, SUM(dur) AS total_dur
FROM tab2
GROUP BY xxx)
tab2 ON tab1.number=tab2.xxx
WHERE total_dur >=10
but how do I also consider the second 'yyy' column?

You can use OR in the join condition to check two columns. Using HAVING might also make the query a bit more readable.
SELECT name FROM tab1
JOIN tab2 ON xxx = number OR yyy = number
GROUP BY name
HAVING SUM(dur) >= 10

You can unpivot the data. In Postgres, I would suggest a lateral join:
SELECT tab1.name
FROM tab1 INNER JOIN
(SELECT v.col, SUM(dur) AS total_dur
FROM tab2 CROSS JOIN LATERAL
(VALUES (tab2.xxx), (tab2.yyy)) v(col)
GROUP BY v.col
) tab2
ON tab1.number = tab2.col
WHERE total_dur >= 10;
Here is a db<>fiddle.

Related

How to combine multiple SELECT statements into a single query & get a single result output

I have multiple SELECT queries which is ran against different tables.
The output of all the queries have the same number of rows (every query when ran individually will have the same number of rows). Is there a way I can combine the output of all these queries into a single result? (Keep out from first query and add the output of next query as a column to the output of the next query). I dont want to save these tables into database as I am just doing some validation testing.
Example:
SELECT AAA,BBB,CCC FROM Table1
SELECT Table2.DDD, Table1.AAA
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA
I tried writing combining the query as
SELECT Table1.AAA,Table1.BBB,Table1.CCC,T1.DDD
FROM Table1,
(SELECT Table2.DDD, Table1.AAA
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA)T1
I tried doing the above combined query, but instead of getting 11 rows as output (both queries above had result of 11 rows), I am getting 35 rows as output.
Hope the question made sense!
You'll need to specify a criteria to match each row the first query with which row of the second query.
If, for example, the column AAA is unique in both queries and you want to match rows with the same values you could do:
select a.*, b.*
from (
SELECT AAA,BBB,CCC FROM Table1
) a
full join join (
SELECT Table2.DDD, Table1.AAA
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA
) b on b.aaa = a.aaa
If there aren't any clear matching rules, you can produce an artificial row number on each result set and use it to match rows. For example:
select
a.aaa, a.bbb, a.ccc,
b.ddd, b.aaa
from (
SELECT AAA, BBB, CCC,
row_number() over(order by aaa) as rn
FROM Table1
) a
full join join (
SELECT Table2.DDD, Table1.AAA,
row_number() over(order by table1.aaa, table2.ddd) as rn
FROM Table2
INNER JOIN Table1
ON Table1.AAA = Table2.AAA
) b on b.rn = a.rn
If you have several results and want to have all of them as additional columns you can simply use ",":
create table temp1 as select '1' as c1 from DUAL;
create table temp2 as select '2' as c2 from DUAL;
create table temp3 as select '3' as c3 from DUAL;
select a.c1, b.c2, c.c3 from temp1 a, (select c2 from temp2) b, (select c3 from temp3) c;
An alternative could also be that you want to have all the results as additional rows then you would use UNION ALL between the individual results.

Join table and pick rows where for given id exists only one value

I don't know, if I made good title, but please let me visualize this.
So I have two tables and for given case I need to select row where payment currency was ONLY in EUR.
Correct document Id's will be: 2, 3, 4, 5
These are overall bigger tables with 900k+ records.
Can you please suggest me how query should look?
use correlated subquery with not exists
select distinct a.document_id from tablename a inner join tablename b b on a.document_id=b.payment_docid
where not exists
(select 1 from tablename b1 where b1.payment_docid=b.payment_docid and currency<>'EUR')
Try this query:
select payment_docId from MyTable
group by payment_docId
having max(currency) = 'EUR'
and min(currency) = 'EUR'
or you could use having count(*) = 1 with min or max as well.
use corelated subquery
select t1.* from table2 as t1
where exists( select 1 from table2 t2 where t1.payment_docid=t2.payment_docid
having count(distinct currency)=1)
and currency='EUR'
It is possible to use INNER JOIN with the following conditions to get all rows:
SELECT
pd.payment_doc_id
, pd.currency
FROM DocTable dt
INNER JOIN PaymentDocs pd
ON dt.document_id = pd.payment_doc_id AND pd.currency IN ('EUR')
If you want distinct rows, then you can apply operator GROUP BY:
SELECT
pd.payment_doc_id
, pd.currency
FROM DocTable dt
INNER JOIN PaymentDocs pd
ON dt.document_id = pd.payment_doc_id AND pd.currency IN ('EUR')
GROUP BY pd.payment_doc_id
, pd.currency
Aggregation is the only efficient want :
select doc_id
from table t
group by doc_id
having min(currency) = max(currency) and min(currency) = 'EUR';

DISTINCT in JOIN

I have a question in Oracle SQL.
To simplify my problem, let's say I have two tables:
TAB1: TAB2:
Usr Fruit Fruit Calories
1 A A 100
1 A B 200
1 A C 150
1 C D 400
1 C E 50
2 A
2 A
2 E
It's important that there are double entries in TAB1.
Now I want to know the calories for usr 1. But by joining both tables
SELECT TAB2.calories from TAB1
JOIN TAB2 ON TAB1.Fruit = TAB2.Fruit
WHERE TAB1.Usr = 1;
I get double results for the double entries. I could of course use distinct in the header, but is there a possibility to distinct the values (to A and C) directly in the join? I am sure that would improve my (much larger) performance.
Thanks!
I'm a big fan of the semi-join. For tables this small, it won't matter, but for larger tables it can make a big difference:
select
tab2.calories
from tab2
where exists (
select null
from tab1
where tab1.fruit = tab2.fruit and tab1.usr = 1
)
Try as this:
SELECT TAB2.calories
from (select distinct usr, fruit from TAB1) as T1
JOIN TAB2 ON T1.Fruit = TAB2.Fruit
WHERE T1.Usr = 1;
You should do distinct before the join
select sum(tab2.calories) as TotalCalories
from (select distinct tab1.*
from tabl
) t1 join
tab2
on t1.fruit = tab2.fruit
where t1.user = 1;
Also, to add the values, use an aggregation function.
since you select nothing in tabA and maybe you have some usefull index, i'd go for an IN instead of the join
SELECT TAB2.calories
FROM TAB2
WHERE TAB2.Fruit IN ( SELECT TAB1.Fruit FROM TAB1 WHERE TAB1.Usr = 1)
i'm pretty sure this one will take longer but you can still try:
SELECT TAB2.calories
FROM TAB2
WHERE TAB2.Fruit IN ( SELECT DISTINCT TAB1.Fruit FROM TAB1 WHERE TAB1.Usr = 1)

Select rows having dstinct values for two fields

Pardon me for the title. I have a table like this:
There will be thousands of rows and now I want to select the rows having the same group_id but vr_debit and vr_credit values must not be equal: ie;, in the image shown, none of the rows satisfy this criteria. If there is are two rows, say, (6,500.000,0) and(6,0,600.000), I want them as the result. Hope you get the idea.
Thank you.
Calculate each group using SUM() which is an aggregate function and filter them using HAVING clause.
SELECT GROUP_ID, SUM(vr_debit) totalDebit, SUM(vr_credit) totalCredit
FROM TableName
GROUP BY GROUP_ID
HAVING SUM(vr_debit) <> SUM(vr_credit)
if you want to get the uncalculated rows, you can join it on the subquery.
SELECT a.*
FROM TableName a
INNER JOIN
(
SELECT GROUP_ID
FROM TableName
GROUP BY GROUP_ID
HAVING SUM(vr_debit) <> SUM(vr_credit)
) b ON a.GROUP_ID = b.GROUP_ID
SQLFiddle Demo (for both queries)
Perhaps:
SELECT group_ID,
vr_debit,
vr_credit
FROM
dbo.TableName T1
WHERE
EXISTS(
SELECT 1 FROM dbo.TableName T2
WHERE T1.group_ID = T2.group_ID
AND T1.vr_debit <> T2.vr_debit
AND T1.vr_credit<> T2.vr_credit
AND T1.vr_debit <> T2.vr_credit
)
Also you can use this option
SELECT *
FROM dbo.test64 t
WHERE EXISTS (
SELECT 1
FROM dbo.test64 t2
WHERE t.group_id = t2.group_id
HAVING SUM(t2.vr_debit) - SUM(t2.vr_credit) != 0
)
Demo on SQLFiddle

Multiple count based on dynamic criteria

I have two database for which I want to compare the amount of times a case appears.
TAB1:
ID Sequence
A2D 1
A2D 2
A2D 3
A3D 1
TAB2:
ID Sequence
A2D 1
A2D 2
A3D 1
A3D 2
Now, for this example, I am trying to get this result:
ID Table1 Table2
A2D 3 2
A3D 1 2
I have tried these code without any success:
SELECT R1.ID as ID, COUNT(R1.ID) as Table1,
COUNT(R2.ID) as Table2
FROM TAB1 AS R1, TAB2 AS R2
WHERE R1.ID = R2.ID
GROUP BY R1.ID
This one gave me wrong count values...
Also, this one simply crash:
select
(
select count(*) as Table1
from TAB1
where ID = R1.ID
),(
select count(*) as Table2
from TAB2
where ID= R1.ID
)
FROM TAB1 AS R1
As you can see though, I am trying to have my criteria dynamic. Most examples I found were including basic hard-coded criteria. But for my case, I want the query to look at my first table ID, count the amount of time it appears, do it for the 2nd table with the same ID, then move on to the next ID.
If my question lacks information or is confusing just ask me, I'll do my best to be more precise.
Thanks in advance !
Here I am using a UNION ALL as a subquery
SELECT ID, SUM(T1) AS Table1, SUM(T2) AS Table2
FROM
(SELECT ID, COUNT(ID) AS T1, 0 AS T2 FROM TAB1 GROUP BY ID
UNION ALL
SELECT ID, 0 AS T1, COUNT(ID) AS T2 FROM TAB2 GROUP BY ID)
GROUP BY ID
HAVING SUM(T1)>0 AND SUM(T2)>0
I used a different approach, but unfortunately I have to use two queries, i still don't know if they can be combined together. The first one is just for making sums of both tables, and combining the results:
SELECT "Tab1" AS [Table], Tab1.ID, Count(*) AS Total
FROM Tab1
GROUP BY "Tab1", Tab1.ID
UNION SELECT "Tab2" AS [Table], Tab2.ID, Count(*) AS Total
FROM Tab2
GROUP BY "Tab2", Tab2.ID
and, since Access supports Pivot queries, you can use this:
TRANSFORM Sum(qrySums.[Total]) AS Total
SELECT qrySums.[ID]
FROM qrySums
GROUP BY qrySums.[ID]
PIVOT qrySums.[Table];
Not sure if I understand your question, but you could try something like this:
SELECT DISTINCT t.ID,
(SELECT COUNT(ID) FROM R1 WHERE ID = t.ID) AS table1,
(SELECT COUNT(ID) FROM R2 WHERE ID = t.ID) AS table2
FROM table1 t
To get the desired results, I broke it down into two sub-queries (R1SQ and R2SQ) and a main UNION query - R1R2 that uses inner, left and right joins to include all row entries including those rows that do not appear in both tables:
R1SQ
SELECT R1.Builder, Count(R1.Builder) AS Table1
FROM R1
GROUP BY R1.Builder;
R2SQ
SELECT R2.Builder_E, Count(R2.Builder_E) AS Table2
FROM R2
GROUP BY R2.Builder_E;
R1R2
SELECT R1SQ.Builder, R1SQ.Table1, R2SQ.Table2
FROM R1SQ INNER JOIN R2SQ ON R1SQ.Builder = R2SQ.Builder_E
UNION
SELECT R1SQ.Builder, R1SQ.Table1, 0 AS Table2
FROM R1SQ LEFT JOIN R2SQ ON R1SQ.Builder = R2SQ.Builder_E
WHERE (((R2SQ.Builder_E) Is Null))
UNION
SELECT R2SQ.Builder_E, 0 AS Table1, R2SQ.Table2
FROM R1SQ RIGHT JOIN R2SQ ON R1SQ.Builder = R2SQ.Builder_E
WHERE (((R1SQ.Builder) Is Null))
ORDER BY R1SQ.Builder;