SQL - summarize results from multiple tables - sql

I have the following simple SQL query that I need to run on 3 tables:
SELECT
A.date,
SUM(A.number)
FROM A
GROUP BY
A.date
But I have two other tables (B and C) on which I'd like to run the same query. And combine the results into one table as output.
I am expecting the output to look something like:
date
A.number
B.number
C.number
2022
12322.1
9999999
888888

We can try the following union approach:
SELECT
date,
SUM(CASE WHEN src = 'A' THEN number ELSE 0 END) AS A_sum,
SUM(CASE WHEN src = 'B' THEN number ELSE 0 END) AS B_sum,
SUM(CASE WHEN src = 'C' THEN number ELSE 0 END) AS C_sum
FROM
(
SELECT date, number, 'A' AS src FROM A
UNION ALL
SELECT date, number, 'B' FROM B
UNION ALL
SELECT date, number, 'C' FROM C
) t
GROUP BY date
ORDER BY date;

Here is my approach:
Create Table TableA
(
Dates Date,
Number Int
)
GO
Create Table TableB
(
Dates Date,
Number Int
)
GO
Create Table TableC
(
Dates Date,
Number Int
)
GO
Insert Into TableA
Values ('2023-01-01', 100000),
('2023-01-02',30000)
GO
Insert Into TableB
Values ('2023-01-01', 200000),
('2023-01-02',10000)
GO
Insert Into TableC
Values ('2023-01-01', 400000),
('2023-01-02',20000)
GO
SELECT * from
(
Select *,'A' Det from TableA
UNION ALL
Select *,'B' from TableB
UNION ALL
Select *,'C' from TableC
)ABC
PIVOT
(SUM(ABC.Number) FOR Det IN (A,B,C))
XYZ
DROP TABLE TableA
DROP Table TableB
DROP table TableC

IMO best option is to create calendar first and then left join created calendar with different tables:
Calendar is important to gather data from join.
And i'ts quite odd if you have column date as year.
In my oppinion it's to small level of complexity.
But ok. Let's say that you have only year.
Create table with years.
Create Table Years
(
years int
)
next:
INSERT INTO Years(years )
VALUES
(2022),(2021),(2020),(2019),(2018),(2017),(2016),(2015)
eg.
SELECT
y.*,
sum(a.number) as SumA,
sum(b.number) as SumB,
sum(c.number) as SumC
FROM Years as y
left join
table_a a
on
y.years=a.date
left join
table_b b
on
y.years=b.date
left join
table_c c
on
y.years=c.date
GROUP BY
y.years
Hopefully this helps!
Please let me know if it works as you wanted.

Related

What is the bigquery sql inner join equivalent for rows?

I have the following 2 tables:
I would like to create a table where
all rows of table 1 are included
if the timestamp of any row of table 2 falls in between the timestamp and endTime of any row of table 1, then include the row.
The resultant table would like:
There are columns/fields that are common to both tables, but I haven't included them for brevity. Basically, I am looking for the equivalent of an inner join operation but then instead of adding the rows of table 2 as columns, add them as rows. I have written a sample code whilst experimenting with inner join as below:
WITH table_a AS (
SELECT 'x' AS event, 1 AS timestamp, 5 AS endtime, 'a' AS field1
UNION ALL SELECT 'x', 100, 200, 'b'
),
table_b AS (
SELECT 'y' AS event, 2 AS timestamp, 'm' AS field2
UNION ALL SELECT 'y', 25, 'n'
UNION ALL SELECT 'y', 150, 'o'
)
SELECT
table_a.*,
table_b.*
FROM table_a JOIN table_b
Any thoughts what bigquery sql functions I can use?
Use below
select *, null field2 from table_a union all
select distinct b.event, b.timestamp, null, cast(null as string), field2
from table_b b
join table_a a
on b.timestamp between a.timestamp and a.endtime
if applied to sample data in your question - output is

how to SUM two columns in different table between two date

this my query but result false where number row different , that's to say whenever tableA select 2 row and tableB select 3 result is false
select sum(tableA.value)+sum(tableB.value1) )
from tableA,tableB
where tableA.data between '2016-01-21' and '2016-03-09'
and tableB.date2 between '2016-01-21' and '2016-03-09'
You need to do the sums in subqueries before joining. A simple rule: never use commas in the from clause.
select coalesce(avalue, 0) + coalesce(bvalue, 0)
from (select sum(a.value) as avalue
from tableA a
where a.data between '2016-01-21' and '2016-03-09'
) a cross join
(select sum(b.value) as bvalue
from tableB b
where b.data between '2016-01-21' and '2016-03-09'
) b;
OK . So here's what my understanding is.
You are trying to sum up two columns from two different tables and get the sum of the summed up columns. isn't ?? Correct me if I am wrong.If this is the case then
A Simple Subquery Can Come To Your Rescue.
Select
(Select SUM(value) From tableA
where data between '2016-01-21' and '2016-03-09') +
(Select SUM(value1) From tableB
where date2 between '2016-01-21' and '2016-03-09') FinalValue

Count Two Tables on shared date in Postgresql

I have two separate customer tables A and B. I am trying to count the customers created in A and B in the same query by date. I can get the right data with Union All but not properly grouped.
I want the data like so:
date,count A created, count B created
4/15/2015,1,5
Instead of:
date, count
4/15/2015, 1
4/15/2015, 5
Appreciate the help!
Just use a cte, just have to be carefull if you dont have date in every day. In that case you would need a date table to get 0 when no sales.
Also try not use reserved words like date as fieldnames
with countA as (
SELECT date, count(*) as CountA
from tableA
group by date
),
countB as (
SELECT date, count(*) as CountB
from tableB
group by date
)
SELECT A.date, A.CountA, B.CountB
FROM CountA A
INNER JOIN CountB B
ON A.date = B.date
With a table AllDates to solve day without sales
SELECT T.date,
CASE
WHEN A.CountA IS NULL THEN 0
ELSE A.CountA
END as CountA,
CASE
WHEN B.CountB IS NULL THEN 0
ELSE B.CountB
END as CountB
FROM AllDates T
LEFT JOIN CountA A
ON T.date = A.date
LEFT JOIN CountB B
ON T.date = B.date
select a.dte
,a.count a_created
,b.count b_created
from
(select dte,count(*)from table_a group by dte) a
,(select dte,count(*)from table_b group by dte) b
where b.dte=a.dte
SQLFIDDLE DEMO
OR
You can use achieve this by using PostgreSQL's tablefunc
start bty creating CREATE EXTENSION if not exists tablefunc;
and following as an example
create table table_a (dte date,is_created int);
create table table_b (dte date,is_created int);
insert into table_a values('2015-10-07',1);
insert into table_a values('2015-10-07',1);
insert into table_a values('2015-10-07',1);
insert into table_a values('2015-10-07',1);
insert into table_a values('2015-10-07',1);
insert into table_b values('2015-10-07',2);
by using crosstab() the select should be
SELECT *
FROM crosstab(
'select dte,''a_created'' col,count(*) created from table_a group by dte
union all
select dte, ''b_created'' col,count(*) created from table_b group by dte')
AS ct("date" DATE, "a_created" BIGINT, "b_created" BIGINT);

select a set of values as a column without CREATE

I'm trying to write a query that will return all QUERY_ID values alongside all matching TABLE_ID values, where QUERY_ID is not specified in any table, and I can't create tables, so have to specify it in the query itself:
QUERY_ID TABLE_ID
1 1
2 NULL
3 3
4 4
5 NULL
I feel like there ought to be a simple way to do this, but I can't think of it for the life of me. Any help would be wonderful. Thanks!
select q.QUERY_ID, t.TABLE_ID
from (
select 1 as QUERY_ID
union all
select 2
union all
select 3
union all
select 4
union all
select 5
) q
left outer join MyTable t on q.QUERY_ID = t.TABLE_ID
one way by using the built in master..spt_values table
SELECT number AS QUERY_ID,TABLE_ID
FROM master..spt_values v
LEFT JOIN YourTable y ON y.QUERY_ID = y.TABLE_ID
WHERE TYPE = 'p'
AND number > 0
AND number <= (SELECT COUNT(*) FROM YourTable)
order by QUERY_ID
are you able to create #temp tables...can you do this?
create table #temp(QUERY_ID int identity,TABLE_ID varchar(200))
insert #temp(TABLE_ID)
select TABLE_ID
from YourTable
select * from #temp
order by QUERY_ID
drop table #temp
or like this
select identity(int,1,1) as QUERY_ID,TABLE_ID
into #temp
from YourTable
select * from #temp
order by QUERY_ID
On sql server 2005 and up there is the row_number function so maybe a reason to upgrade :-)

TSQL Comparing two Sets

When two sets are given
s1 ={ a,b,c,d} s2={b,c,d,a}
(i.e)
TableA
Item
a
b
c
d
TableB
Item
b
c
d
a
How to write Sql query to display "Elements in tableA and tableB are equal". [Without using SP or UDF]
Output
Elements in TableA and TableB contains identical sets
Use:
SELECT CASE
WHEN COUNT(*) = (SELECT COUNT(*) FROM a)
AND COUNT(*) = (SELECT COUNT(*) FROM b) THEN 'Elements in TableA and TableB contains identical sets'
ELSE 'TableA and TableB do NOT contain identical sets'
END
FROM (SELECT a.col
FROM a
INTERSECT
SELECT b.col
FROM b) x
Test with:
WITH a AS (
SELECT 'a' AS col
UNION ALL
SELECT 'b'
UNION ALL
SELECT 'c'
UNION ALL
SELECT 'd'),
b AS (
SELECT 'b' AS col
UNION ALL
SELECT 'c'
UNION ALL
SELECT 'd'
UNION ALL
SELECT 'a')
SELECT CASE
WHEN COUNT(*) = (SELECT COUNT(*) FROM a)
AND COUNT(*) = (SELECT COUNT(*) FROM b) THEN 'yes'
ELSE 'no'
END
FROM (SELECT a.col
FROM a
INTERSECT
SELECT b.col
FROM b) x
Something like this, using FULL JOIN:
SELECT
CASE
WHEN EXISTS (
SELECT * FROM s1 FULL JOIN s2 ON s1.Item = s2.Item
WHERE s1.Item IS NULL OR s2.Item IS NULL
)
THEN 'Elements in tableA and tableB are not equal'
ELSE 'Elements in tableA and tableB are equal'
END
This has the virtue of short-circuiting on the first non-match, unlike other solutions that require 2 full scans of each table (once for the COUNT(*), once for the JOIN/INTERSECT).
Estimated cost is significantly less than other solutions.
Watch out, I'm gonna use a Cross Join.
Declare #t1 table(val varchar(20))
Declare #t2 table(val varchar(20))
insert into #t1 values ('a')
insert into #t1 values ('b')
insert into #t1 values ('c')
insert into #t1 values ('d')
insert into #t2 values ('c')
insert into #t2 values ('d')
insert into #t2 values ('b')
insert into #t2 values ('a')
select
case when
count(1) =
(((Select count(1) from #t1)
+ (Select count(1) from #t2)) / 2.0)
then 1 else 0 end as SetsMatch from
#t1 t1 cross join #t2 t2
where t1.val = t2.val
My monstrocity:
;with SetA as
(select 'a' c union
select 'b' union
select 'c')
, SetB as
(select 'b' c union
select 'c' union
select 'a' union
select 'd'
)
select case (select count(*) from (
select * from SetA except select * from SetB
union
select * from SetB except select * from SetA
)t)
when 0 then 'Equal' else 'NotEqual' end 'Equality'
Could do it with EXCEPT and a case
select
case
when count (1)=0
then 'Elements in TableA and TableB contains identical sets'
else 'Nope' end from (
select item from s1
EXCEPT
select item from s2
) b
Since this thread was very helpful to me, I thought I'd share my solution.
I had a similar problem, perhaps more generally applicable than this specific single-set comparison. I was trying to find the id of an element that had a set of multi-element child elements that matched a query set of multi-element items.
The relevant schema information is:
table events, pk id
table solutions, pk id, fk event_id -> events
table solution_sources, fk solutionid -> solutions
columns unitsourceid, alpha
Query: find the solution for event with id 110 that has the set of solution_sources that match the set of (unitsourceid, alpha) in ss_tmp. (This can also be done without the tmp table, I believe.)
Solution:
with solutionids as (
select y.solutionid from (
select ss.solutionid, count(ss.solutionid) x
from solutions s, solution_sources ss
where s.event_id = 110 and ss.solutionid = s.id
group by ss.solutionid
) y where y.x = ( select count(*) from ss_tmp )
)
select solutionids.solutionid from solutionids where
(
select case
when count(*) = ( select count(*) from ss_tmp ) then true
else false
end
from
( SELECT unitsourceid, alpha FROM solution_sources
where solutionid = solutionids.solutionid
INTERSECT
SELECT unitsourceid, alpha FROM ss_tmp ) x
)
Tested against a test query of 4 items and a test db that had a matching solution (same number of child elements, each that matched), several completely non-matching solutions, and 1 solution that had 3 matching child elements, 1 solution that had all 4 matching child elements, plus an additional child, and 1 solution that had 4 child elements of which 3 of the 4 matched the query. Only the id of the true match was returned.
thanks a lot
-Linus
Use EXCEPT statement
When using the EXCEPT statement to test if two sets contain the same rows, you will need to do the EXCEPT in both directions (A EXCEPT B and B EXCEPT A). If either comparison returns any records, then the sets are different. If no records are returned by either, they are the same.
The nice thing about this is that you can do this comparison with any number of specific columns and NULL values are handled implicitly without having to jump through hoops to compare them.
A good use case for this is verifying that saving a set of records happened correctly, especially when affecting an existing set.
SELECT IsMatching = (1 ^ convert(bit, count(*)))
FROM (
SELECT Mismatched = 1 -- Can be any column name
FROM (
SELECT Item -- Can have additional columns
FROM TableA
EXCEPT
SELECT Item -- Can have additional columns
FROM TableB
) as A
UNION
SELECT Mismatched = 1 -- Can be any column name
FROM (
SELECT Item -- Can have additional columns
FROM TableB
EXCEPT
SELECT Item -- Can have additional columns
FROM TableA
) as A
) as A