Query to calculate the sum from 3 different tables - sql

I have 3 tables
Table A:
Cid acc_id acc balance
1 345 100
1 456 300
2 347 500
Table B:
Cid acc_id acc balance
1 348 100
1 457 300
2 349 500
Table C:
Cid acc_id acc balance
1 340 100
1 457 300
2 344 500
I need to create a single table which gives the sum of balances for each customer across all 3 tables.
Cid. Balance
1. 1200
2. 1500
I need SQL for this purpose. Since customer id is repeating within the table I m confused.

Use union all and aggregation
select cid, sum(balance)
from ((select Cid, acc_id, balance
from a
) union all
(select Cid, acc_id, balance
from b
) union all
(select Cid, acc_id, balance
from c
)
) abc
group by cid;

You can use UNION ALL, as in:
select
cid,
sum(balance) as balance
from (
select * from table_a
union all
select * from table_b
union all
select * from table_c
) x
group by cid

Related

group by and aggregate from tall to wide data in bigquery sql

Hi I want to aggregate group by and change it from tall to wide data in bigquery, how do I do so? I have a lot of sources and here's a sample data.
Here's the table
date
source
price
id
2022-01-01
A
2
1
2022-01-02
A
2
1
2022-01-03
A
4
1
2022-01-04
A
4
1
2022-01-01
B
1
1
2022-01-02
B
1
1
2022-01-03
B
3
1
2022-01-04
B
3
1
2022-01-01
A
2
2
2022-01-02
A
2
2
2022-01-03
A
4
2
2022-01-04
A
4
2
2022-01-01
B
1
2
2022-01-02
B
1
2
2022-01-03
B
3
2
2022-01-04
B
3
2
into
fields of min from price from all source for group by id and min price per source group by id
id
minPrice
minPriceSourceA
minPriceSourceB
1
2.5
3
2
2
2.5
3
2
Here's my current code
with Amin as
(
select
id,source,
min(price) min price
from table
where source ="A"
group by 1,2
),
Bmin as
(
select
id,source,
min(price) min price
from table
where source ="B"
group by 1,2
),
select
t1.id,t1.minprice,
Amin.minprice minPriceSourceA,
Bmin.minprice minPriceSourceB
from(
select
id,source,
min(price) minprice
from table
group by 1,2) t1
left join Amin on t1.id=Amin.id
left join Bmin on t1.id=Bmin.id
The problem is I have over 100 sources and id, if I do query manually the code will be very long. Is there an efficient way to do this?
You can use PIVOT to transpose rows into columns and get the MIN of a list of columns at once:
with sample as (
select "2022-01-01" as date, "A" as source, 2 as price, "1" as id
UNION ALL
select "2022-01-02" as date, "A" as source, 1 as price, "1" as id
UNION ALL
select "2022-01-04" as date, "B" as source, 1 as price, "1" as id
UNION ALL
select "2022-01-04" as date, "A" as source, 2 as price, "2" as id
UNION ALL
select "2022-01-04" as date, "A" as source, 4 as price, "2" as id
UNION ALL
select "2022-01-04" as date, "B" as source, 3 as price, "2" as id
),
min_by_source as (
SELECT * FROM
(SELECT id, source, price FROM sample)
PIVOT(MIN(price) AS minPrice FOR source IN ('A', 'B')) -- add here the others sources
),
min_global as (
SELECT id, MIN(price) AS minPrice
FROM sample
GROUP BY id
)
SELECT *
FROM min_global
JOIN min_by_source USING (id)
Output:
id minPrice minPrice_A minPrice_B
1 1 1 1
2 2 2 3
Consider below option
select * from (
select * except(date),
avg(price) over(partition by id) avgPrice,
min(price) over(partition by id) minPrice
from your_table)
pivot (min(price) minPriceSource for source in ('A', 'B'))
if applied to sample data in your question - output is
The problem is I have over 100 sources and id, if I do query manually the code will be very long. Is there an efficient way to do this?
Use below dynamic version
execute immediate (select '''
select * from (
select * except(date),
avg(price) over(partition by id) avgPrice,
min(price) over(partition by id) minPrice
from your_table)
pivot (min(price) minPriceSource for source in (''' || string_agg(distinct '"' || source || '"') || '''))
'''
from your_table
)

How to union Invoice data and Reconcile data that is not link directly

Invoice table
DocEntry
ObjType
Amount
11
13
200
Reconcile table
ReconNo
Line
SrcObjType
SrcObjEntry
Amount
1
1
24
15
150
1
2
13
11
150
Link: Invoice.ObjType = Reconcile.SrcObjType
and Invoice.DocEntry = Reconcile.SrcObjEntry
Expected result:
DocEntry
ObjType
Amount
11
13
200
15
24
150
I am trying to union the reconcile line that is not link directly to invoice but it is in the same ReconNo with reconciled invoice line. Is this possible in SQL?
Thanks for your help
Maybe this will get you there?
with Invoice (DocEntry, ObjType, Amount) as(
select 11, 13, 200
),
Reconcile (ReconNo,Line,SrcObjType,SrcObjEntry,Amount) as(
select 1,1,24,15,150 union all
select 1,2,13,11,150
),
connection as (
select DocEntry,ReconNo
from Invoice as i
join Reconcile as r on i.DocEntry=r.SrcObjEntry
)
select * from Invoice union all
select SrcObjEntry as DocEntry, SrcObjType as ObjType,Amount
from connection c
join Reconcile r on r.ReconNo = c.ReconNo
where r.SrcObjEntry not in (select DocEntry from invoice)

Agg Functions while Partitioning Data in SQL

I have a table that looks like this:
store_id industry_id cust_id amount gender
1 100 1000 1.00 M
2 100 1000 2.05 M
3 100 1000 3.15 M
4 100 1000 4.00 M
5 100 2000 5.00 F
6 200 2000 5.20 F
7 200 5000 6.05 F
8 200 6000 7.10 F
Here's the code to create this table:
CREATE TABLE t1(
store_id int,
industry_id int,
cust_id int,
amount float,
gender char
);
INSERT INTO t1 VALUES(1,100,1000,1.00, 'M');
INSERT INTO t1 VALUES(2,100,1000,2.05, 'M');
INSERT INTO t1 VALUES(3,100,1000,3.15, 'M');
INSERT INTO t1 VALUES(4,100,1000,4.00, 'M');
INSERT INTO t1 VALUES(5,100,2000,5.00, 'F');
INSERT INTO t1 VALUES(6,200,2000,5.20, 'F');
INSERT INTO t1 VALUES(7,200,5000,6.05, 'F');
INSERT INTO t1 VALUES(8,200,6000,7.10, 'F');
The question I'm trying to answer is: What is the avg. transaction amount for the top 20% of customers by industry?
This should yield these results:
store_id. industry_id avg_amt_top_20
1 100 4.80
2 100 4.80
3 100 4.80
4 100 4.80
5 100 4.80
6 200 7.10
7 200 7.10
8 200 7.10
Here's what I have so far:
SELECT
store_id, industry_id,
avg(CASE WHEN percentile>=0.80 THEN amount ELSE NULL END) OVER(PARTITION BY industry_id) as cust_avg
FROM(
SELECT store_id, industry_id, amount, cume_dist() OVER(
PARTITION BY industry_id
ORDER BY amount desc) AS percentile
FROM t1
) tmp
GROUP BY store_id, industry_id;
This fails on the GROUP BY (contains nonaggregated column 'amount'). What's the best way to do this?
What is the avg. transaction amount for the top 20% of customers by industry?
Based on this question, I don't see why store_id is in the results.
If I understand correctly, you need to aggregate to get the total by customer. Then you can use NTILE() to determine the top 20%. The final step is aggregating by industry:
SELECT industry_id, AVG(total)
FROM (SELECT customer_id, industry_id, SUM(amount) as total,
NTILE(5) OVER (PARTITION BY industry_id ORDER BY SUM(amount) DESC) as tile
FROM t
GROUP BY customer_id, industry_id
) t
WHERE tile = 1
GROUP BY industry_id

SQL query aggregate function with two tables

I'm trying to query some data from SQL such that it sums some columns, gets the max of other columns and the corresponding value from another table. For example,
|table1|
|order id| |id| |shares| |date| other stuff
12345 1 100 05/13/16 XXX
12345 2 200 05/15/16 XXX
12345 3 300 06/12/16 XXX
12345 4 400 02/22/16 XXX
56789 5 1000 03/30/16 XXX
56789 6 200 02/25/16 XXX
22222 7 5000 01/10/16 XXX
|table2|
|id| |price|
1 21.2
2 20.2
3 19.1
4 21.3
5 100.0
6 110.0
7 5.0
I want my output to be:
|shares| |date| |price| other stuff
1000 06/12/16 19.1 max(other stuff)
1200 03/30/16 1000.0 max(other stuff)
5000 01/10/16 5.0 max(other stuff)
The shares have been summed up, the date is max(date), and the price is the price at the corresponding max(date).
So far, I have:
select
orderid, stock, side, exchange,
max(startdate), max(enddate),
sum(shares), sum(execution_price * shares) / sum(shares),
max(limitprice), max(price)
from
table1 t1
inner join
table2 t2 on t2.id = t1.id
where
location = 'CHICAGO'
and startdate > '1/1/2016'
and order_type = 'limit'
group by
orderid, stock, side, exchange
However, this returns:
|shares| |date| |price| |other stuff|
1000 06/12/16 21.3 max(other stuff)
1200 03/30/16 1100.0 max(other stuff)
5000 01/10/16 5.0 max(other stuff)
which isn't the corresponding price for the max(date).
The only link between the two datasets are their id numbers, which is why
inner join
table2 t2 on t2.id = t1.id
is done. No dates in the second table at all. Any help?
Thanks.
You can resolve this using Sub-query. You need not use any aggregate function on price column, just find the max date and then get price of that particular date.Try something like this..
select t5.*, t4.price
from
(select t1.order_id, sum(t1.shares) as shares, max(t1.date) as maxdate, max(other_stuff) as other_stuff
from Table1 t1
inner join
Table2 t2 on t2.id = t1.id
group by t1.order_id) t5
inner join Table1 t3
on t5.maxdate = t3.date and t5.order_id = t3.order_id
inner join Table2 t4
on t3.id = t4.id;
ONLINE DEMO HERE
Try this (don't forget to replace #table1 and #table2 with your own table names):
SELECT Aggregated.shares
, Aggregated.date
, Aggregated.other_stuff
, T2.price
FROM (
SELECT order_id
, SUM(shares) as shares
, MAX(date) as date
, MAX(other_stuff) as other_stuff
FROM #table1 AS T1
GROUP BY order_id
) AS Aggregated
INNER JOIN #table1 AS T1 ON Aggregated.order_id = T1.order_id AND Aggregated.date = T1.date
INNER JOIN #table2 AS T2 ON T2.id = T1.id
So, before I write you a query, you basically want the price during that max date, correct? You have MAX on price, sum of shares, max on limit price, sum on shares again and so on.
My guess is you want the latest price based on the latest date (Max) then run the calculations for the latest date, latest # of shares for that max date, and sum that all together? You're also grouping on ID, Shares, and other things that don't really make sense, it would seem you would want to group on Shares, Side and Exchange but not ID. Looks like you put a max on other things just so they show up without having to group on them, this is not going to work for what you want as long as I think I know what you're looking for =) Let me know and I can definitely help if I know what your end result "specs" are.
I would do a sub-query with a max over partition ordered by date to display the last date price, then do the aggregations on the upper level, here is an example of how it would work.
Sample data
pk id shares date id price
------- --- -------- -------------------------- --- -------
100 1 100 2016-07-08 10:40:34.707 1 50
100 2 200 2016-07-06 10:40:34.707 2 20
101 3 500 2016-07-09 10:40:34.707 3 70
101 4 150 2016-07-07 10:40:34.707 4 80
102 5 300 2016-07-10 10:40:34.707 5 40
Query
with t1 as (
select 100 pk,1 id, 100 shares, getdate()-3 date union all
select 100 pk,2 id, 200 shares, getdate()-5 date union all
select 101 pk,3 id, 500 shares, getdate()-2 date union all
select 101 pk,4 id, 150 shares, getdate()-4 date union all
select 102 pk,5 id, 300 shares, getdate()-1 date ),
t2 as (
select 1 id, 50 price union all
select 2 id, 20 price union all
select 3 id, 70 price union all
select 4 id, 80 price union all
select 5 id, 40 price
)
SELECT pk,sum(shares) shares,max(date) date, max(price) from(
SELECT pk,
shares,
date,
MAX(price) over(partition by pk order by date desc) price
FROM t1
JOIN t2 ON t1.id = t2.id) a
group by pk
Result
pk shares date Price
--- ------- ------------------------ -----
100 300 2016-07-08 10:51:16.023 50
101 650 2016-07-09 10:51:16.023 80
102 300 2016-07-10 10:51:16.023 40

How to select Remain values after subtract with one Fixed value

Need To select Data From One Table After Minus With One Value
this is the question i already asked and this solution for one value input to table and result. but i need this with more input values for different categories and each categories output
for eg(based of previous question)
Table 1
SNo Amount categories
1 100 type1
2 500 type1
3 400 type1
4 100 type1
5 100 type2
6 200 type2
7 300 type2
8 500 type3
9 100 type3
and
values for type1 - 800
values for type2 - 200
values for type3 - 100
and the output need is
for type-1
800 - 100 (Record1) = 700
700 - 500 (record2) = 200
200 - 400 (record3) = -200
The table records starts from record 3 with Balance Values Balance 200
Table-Output
SNo Amount
1 200
2 100
that means if minus 800 in first table the first 2 records will be removed and in third record 200 is Balance
same operation for remain types also and how to do it?
SQLFiddle demo
with T1 as
(
select t.*,
SUM(Amount) OVER (PARTITION BY [Type] ORDER BY [SNo])
-
CASE WHEN Type='Type1' then 800
WHEN Type='Type2' then 200
WHEN Type='Type3' then 100
END as Total
from t
)select Sno,Type,
CASE WHEN Amount>Total then Total
Else Amount
end as Amount
from T1 where Total>0
order by Sno
UPD: If types are not fixed then you should create a table for them, for example:
CREATE TABLE types
([Type] varchar(5), [Value] int);
insert into types
values
('type1',800),
('type2',200),
('type3',100);
and use the following query:
with T1 as
(
select t.*,
SUM(Amount) OVER (PARTITION BY t.[Type] ORDER BY [SNo])
-
ISNULL(types.Value,0) as Total
from t
left join types on (t.type=types.type)
)select Sno,Type,
CASE WHEN Amount>Total then Total
Else Amount
end as Amount
from T1 where Total>0
order by Sno
SQLFiddle demo
UPDATE: For MSSQL 2005 just replace SUM(Amount) OVER (PARTITION BY t.[Type] ORDER BY [SNo]) with (select SUM(Amount) from t as t1
where t1.Type=t.Type
and t1.SNo<=t.SNo)
with T1 as
(
select t.*,
(select SUM(Amount) from t as t1
where t1.Type=t.Type
and t1.SNo<=t.SNo)
-
ISNULL(types.Value,0) as Total
from t
left join types on (t.type=types.type)
)select Sno,Type,
CASE WHEN Amount>Total then Total
Else Amount
end as Amount
from T1 where Total>0
order by Sno
SQLFiddle demo