Find the difference for results from two select - sql

I have two tables:
table_1:
A | B | C
z | x | 12
z | c | 13
z | c | 10
a | s | 14
a | d | 11
table_2:
A | B | C
z | c | 10
z | x | 15
z | x | 11
a | d | 14
a | s | 12
I want to:
- group the tables by A and B
- and find the difference for SUM of C for AB.
I started with:
SELECT A, B, SUM(C) from table_1 GROUP BY A, B;
SELECT A, B, SUM(C) from table_2 GROUP BY A, B;
but I don't know how to JOIN them with adding additional column that is equal
to table_1.sum(C) - table_2.sum(c)
Expected result like:
A | B | sum1 | sum2 | diff
z | x | 12 | 26 | -14
z | c | 23 | 10 | 13
a | s | 14 | 12 | 2
a | d | 11 | 14 | -3

Use join with subquery
select X.A,X.B, sum1, sum2, sum1-sum2 as diff from
(
SELECT A, B, SUM(C) sum1
from table_1 GROUP BY A, B
)X inner join
(
SELECT A, B, SUM(C) sum2
from table_2 GROUP BY A, B
)Y on X.A=Y.A and X.B=Y.B

What do you want to happen when the groups are not the same in the two tables? inner join can be dangerous because groups will disappear.
If you want to keep all groups, then one method is union all/group by:
select a, b, sum(c1) as sum1, sum(c2) as sum2,
(sum(c2) - sum(c1)) as diff
from ((select a, b, c as c1, 0 as c2
from table_1
) union all
(select a, b, 0 as c1, c as c2
from table_2
)
) t
group by a, b

Related

Bigquery: Joining 2 tables one having repeated records and one with count ()

I want to join tables after unnest arrays in Table:1 but the records duplicated after the join because of the unnest.
Table:1
| a | d.b | d.c |
-----------------
| 1 | 5 | 2 |
- -------------
| | 3 | 1 |
-----------------
| 2 | 2 | 1 |
Table:2
| a | c | f |
-----------------
| 1 | 12 | 13 |
-----------------
| 2 | 14 | 15 |
I want to join table 1 and 2 on a but I need also to have the output of:
| a | d.b | d.c | f | h | Sum(count(a))
---------------------------------------------
| 1 | 5 | 2 | 13 | 12 |
- ------------- - - 1
| | 3 | 1 | | |
---------------------------------------------
| 2 | 2 | 1 | 15 | 14 | 1
a can be repeated in table 2 for that I need to count(a) then select the sum after join.
My problem is when I'm joining I need the nested and repeated record to be the same as in the first table but when use aggregation to get the sum I can't group by struct or arrays so I UNNEST the records first then use ARRAY_AGG function but also there was an issue in the sum.
SELECT
t1.a,
t2.f,
t2.h,
ARRAY_AGG(DISTINCT(t1.db)) as db,
ARRAY_AGG(DISTINCT(t1.dc)) as dc,
SUM(t2.total) AS total
FROM (
SELECT
a,
d.b as db,
d.c as dc
FROM
`table1`,
UNNEST(d) AS d,
) AS t1
LEFT JOIN (
SELECT
a,
f,
h,
COUNT(*) AS total,
FROM
`table2`
GROUP BY
a,f,h) AS t2
ON
t1.a = t2.a
GROUP BY
1,
2,
3
Note: the error is in the total number after the sum it is much higher than expected all other data are correct.
I guess your table 2 contains is not unique for column a.
Lets assume that the table 2 looks like this:
a
c
f
1
12
13
2
14
15
1
100
101
There are two rows where a is 1. Since b and f are different, the grouping does not solve this ( GROUP BY a,f,h) AS t2) and counts(*) as total is one for each row.
a
c
f
total
1
12
13
1
2
14
15
1
1
100
101
1
In the next step you join this table to your table 1. The rows of table1 with value 1 in column a are duplicated, because table2 has two entries. This lead to the fact that the sum is too high.
Instead of unnesting the tables, I recommend following approach:
-- Creating of sample data as given:
with tbl_A as (select 1 a, [struct(5 as b,2 as c),struct(3,1)] d union all select 2,[struct(2,1)] union all select null,[struct(50,51)]),
tbl_B as (select 1 as a,12 b, 13 f union all select 2,14,15 union all select 1,100,101 union all select null,500,501)
-- Query:
select *
from tbl_A A
left join
(Select a,array_agg(struct(b,f)) as B, count(1) as counts from tbl_B group by 1) B
on ifnull(A.a,-9)=ifnull(B.a,-9)

Join two tables, get all results from first table

So I have two tables. Let's say this is the structure of the tables:
TABLE A | TABLE B |
-----------------------------------------|
ID | div | ID | date | val |
-----------------------------------------|
A | a | A | d1 | 22 |
B | b | B | d2 | 10 |
C | c | C | d3 | 9 |
F | l | F | d1 | 10 |
What I want is to have this result:
row 1: A, a, null, null
row 2: B, b, d2, 10
row 3: C, c, null, null
row 4: F, l, d1, 10
It's a left JOIN but I want to retrieve only the values that have val = 10.
I am using SQLite. I have tried many answers from different threads without any success.
You are looking for left join:
select a.*, b.date, b.val
from a left join
b
on a.id = b.id and b.val = 10
order by a.id;

How to distinguish between real NULL and formal NULL in Postgres ROLLUP?

I am trying to determine what "level" of a ROLLUP report each given row belongs to. When initial data contains no NULLs, then it is possible just count nulls in every row (amount of null cells is the same for each given level/layer of grouping), although it also does not appear to me as a beautiful solution.
In case when initial data contains NULLs this workaround works no more: in the example query results table you see that <null> comes from real nulls, and (null) is a standard NULL placeholder for a grouped cell.
I expect to find something similar to "virtual columns as in hierarchical queries (like LEVEL, PATH, etc.).
Is there a natural way in PostgreSQL v12 to determine a level of a row in report built with ROLLUP (and in general with GROUPING SETS)?
Example of ROLLUP query result:
select a, b, sum(d.c)
from(
select null as a, 2 as b, 1 as c
union all
select null as a, 3 as b, 1 as c
union all
select 'a1' as a, 4 as b, 1 as c
union all
select 'a1' as a, 5 as b, 1 as c
union all
select 'a2' as a, 6 as b, 1 as c
) d GROUP by ROLLUP (d.a, d.b)
| a | b | sum |
--------------------------
| (null) | (null) | 5 |
| a1 | 5 | 1 |
| <null> | 2 | 1 |
| a1 | 4 | 1 |
| a2 | 6 | 1 |
| <null> | 3 | 1 |
| a2 | (null) | 1 |
| <null> | (null) | 2 |
| a1 | (null) | 2 |
--------------------------
Use Grouping, kind of
select case when grouping(a) = 1 then 'Total' else cast(a as varchar(20)) end a,
case when grouping(b) = 1 then 'Total' else cast(b as varchar(20)) end b, sum(d.c)
from(
select null as a, 2 as b, 1 as c
union all
select null as a, 3 as b, 1 as c
union all
select 'a1' as a, 4 as b, 1 as c
union all
select 'a1' as a, 5 as b, 1 as c
union all
select 'a2' as a, 6 as b, 1 as c
) d GROUP by ROLLUP (d.a, d.b)
order by grouping(a), a, grouping(b), b

SQL Server UNION and offset primary key

I would like to union two tables, and in the results, have a column of the second table be offset by the max value of that column in the first table.
Example: suppose I have two tables where both have the same columns:
TableA
a | b | c
1 | 1 | 1
2 | 2 | 2
TableB
a | b | c
1 | 6 | 6
2 | 7 | 7
I want to be able to perform something like a UNION ALL which results in:
Results
a | b | c
1 | 1 | 1
2 | 2 | 2
3 | 6 | 6
4 | 7 | 7
By performing an actual UNION ALL my results are:
Results
a | b | c
1 | 1 | 1
2 | 2 | 2
1 | 6 | 6
2 | 7 | 7
UPDATE: I would also like to put this into a VIEW, which is complicating it for me.
Thanks in advance
You can get the max a value from table A and add it to column a from table B.
select a,b,c from tblA
union all
select a+t.max_a,b,c from tblB
cross join (select max(a) as max_a from tblA) t
does it value of column [a] for both table needs to follow original value ?
select a = row_number() over (order by a), b, c
from
(
select a, b, c from tableA
union all
select a, b, c from tableB
) d
alternatively, use row_number() to generate a sequence for tableb
select a = coalesce(a, max(a) over() + row_number() over(order by a)),
b, c
from
(
select a, b, c
from tableA
union all
select a = NULL, b, c
from tableB
) d
order by a

Single row for multiple case in a select

I need a solution for the below senario
I have a table temp with columns: a, b, c, d and the data looks like this:
TABLE TEMP
+---+----+----+----+
|a | b | c | d |
+===+====+====+====+
| 1 | 1 | 1 | m |
| 1 | 2 | 1 | d |
| 1 | 3 | 1 | w |
| 2 | 1 | 1 | m |
| 2 | 2 | 1 | d |
| 2 | 2 | 1 | w |
+---+----+----+----+
QUERY
SELECT CASE WHEN B=1 AND C=1 THEN D END as T1,
CASE WHEN B=2 AND C=1 THEN D END as T2,
CASE WHEN B=3 AND C=1 THEN D END as T3
FROM TEMP
WHERE A=1
The above query gives multiple rows with null values where value is not present
I need a result set with a single row that looks like this:
Expected Result
+------+-------+------+
| T1 | T2 | T3 |
+======+=======+======+
| m | d | w |
+------+-------+------+
Do like this (using CTE)
QUERY
WITH
CTE1 as (select top 1 d as T1 from temp where b=1 and c=1),
CTE2 as (select top 1 d as T2 from temp where b=2 and c=1),
CTE3 as (select top 1 d as T3 from temp where b=3 and c=1)
select CTE1.*, CTE2.*, CTE3.*
FROM CTE1 CROSS JOIN CTE2 CROSS JOIN CTE3
SQL fiddle
About the multiple CTE
Please let me whether it works!