Full Join And Distribute Evenly Based on Count in SQL - sql

I have two tables that I want to join:
Table A
Date Gran1 Gran2 Gran3
1/1/18 A B CD
1/1/18 A B EF
1/2/18 A B GF
1/2/18 A B EF
1/2/18 A B FR
1/2/18 A L EF
Table B
Date Gran1 Gran2 Value1 Value2
1/1/18 A B 100 150
1/2/18 A B 200 80
1/2/18 A L 500 30
Table B does not have the same granularity as Table A. I want to join Table B to Table A and distribute the Values I am joining by the count of occurences Date, Gran1, and Gran2 occur.
My final result should look like this:
Date Gran1 Gran2 Gran3 Value1 Value2
1/1/18 A B CD 50 75
1/1/18 A B EF 50 75
1/2/18 A B GF 66.67 26.67
1/2/18 A B EF 66.67 26.67
1/2/18 A B FR 66.67 26.67
1/2/18 A L EF 500 30
Any help would be great, thanks!

You can try this query
Select a1.date1,
a1.gran1,
a1.gran2,
a1.gran3,
(b.value1/a2.xCount) as value1,
(b.value2/a2.xCount) as value2
from #tableA A1
Inner join #tableB B on A1.date1 = B.date1
and a1.gran1 = b.gran1
and a1.gran2 = b.gran1
inner join (select date1, gran1, gran2, count(*) xCount
from #tableA
group by date1, gran1, gran2) A2 on A1.date1 = A2.date1
and a1.gran1 = a2.gran1
and a1.gran2 = a2.gran2

Would this query work?
SELECT a.date,
a.gran1,
a.gran2,
a.gran3,
b.value1/gran_count AS value1,
b.value2/gran_count AS value2
FROM table_a a
INNER JOIN table_b b
ON (a.date = b.date
AND a.gran1 = b.gran1
AND a.gran2 = b.gran2)
INNER JOIN (
SELECT date, gran1, gran2, count(*) AS gran_count
FROM table_a
GROUP BY date, gran1, gran2
) sub ON (a.date = sub.date
AND a.gran1 = sub.gran1
AND a.gran2 = sub.gran2);
I don't have access to SQL right now so I can't verify the data (or even if I've missed something in the syntax), but I'm attempting to find the COUNT of each combination of date/gran1/gran2 in a subquery, and then use that in a division in the main query.
Both table_b and the subquery (which I've called "sub") are joined to table_a.
There may be a more efficient way of doing this query using two joins instead of three, but nothing comes to mind right now.

Related

How to identify non-existing keys with reference to a table that has all mandatory keys, SQL?

I have the table 'Table01' which contains the keys that should be mandatory:
id
1
2
3
4
And I also have the table 'Table02' which contains the records to be filtered:
id
customer
weight
1
a
100
2
a
300
3
a
200
4
a
45
1
b
20
2
b
100
3
b
17
1
c
80
4
c
90
2
d
30
3
d
30
4
d
50
So I want to identify which are the mandatory id's that the table 'Table02' does not have, and in turn identify which is the 'customer' of each id's that the table 'Table02' does not have.
The resulting table should look like this:
customer
id
b
4
c
2
c
3
d
1
What I have tried so far is a 'rigth join'.
proc sql;
create table table03 as
select
b.id
from table02 a
right join table01 b
on a.id=b.id
where a.id is null;
run;
But that query is not identifying all the id's that should be mandatory.
I hope someone can help me, thank you very much.
here is one way:
select cl.customerid , a.id
from
Table1 a
cross join
( select customerid
from table2
group by customerid
) cl
where not exists ( select 1 from table2 b
where b.customerid = cl.customerid
and b.id = a.id
)
You can use an EXCEPT between two sub-selects. The first creates a matrix of all possibilities, and the except table is a selection of the extant customers.
Example:
data ids;
do id = 1 to 4; output; end;
run;
data have;
input id customer $ weight;
datalines;
1 a 100
2 a 300
3 a 200
4 a 45
1 b 20
2 b 100
3 b 17
1 c 80
4 c 90
2 d 30
3 d 30
4 d 50
run;
proc sql;
create table want(label='Customers missing some ids') as
select matrix.*
from
(select distinct have.customer, ids.id from have, ids) as matrix
except
(select customer, id from have)
;
quit;
If you are doing it in SQL server. Something like #eshirvana above posted, but also you can use with cte:
;with cte as
(
SELECT t1.id, t2.Customer
FROM Table01 t1
cross join (select distinct customer from Table02)
)
SELECT a.customer, a.id FROM cte a
LEFT JOIN Table02 b
ON a.id=b.id AND a.customer=b.customer
where b.id is null

How to join only latest date values from another table and prevent duplication

I'm trying to lookup a unique value from table b and get it into table a.
Table b stores multiple values that are changing by date.
I would like to join but only getting the values with the latest date from table b.
Table a
Unique ID
1
2
Table b
Date Unique ID Price
01/01/2019 1 100
01/02/2019 1 101
01/03/2019 1 102
01/01/2019 2 90
01/02/2019 2 91
01/03/2019 2 92
Expected result
Unique ID Price Date
1 102 01/03/2019
2 92 01/03/2019
Appreciate your help!
Have a sub-query that returns each UniqueID together with its max date. IN that result.
select * from tablename
where (UniqueID, date) in (select UniqueID, max(date)
from tablename
group by UniqueID)
You want correlated subquery :
select b.*
from tableb b
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = b.UniqueID);
If you want to go with JOIN then you can do JOIN with subquery :
select a.UniqueID , b.Price, b.Date
from tablea a inner join
tableb b
on b.UniqueID = a.UniqueID
where b.date = (select max(b1.date) from tableb b1 where b1.UniqueID = a.UniqueID);
A correlated subquery?
select b.*
from b
where b.date = (select max(b2.date) from b b2 where b2.unique_id = b.unique_id);

SQL apply different where condition (filter) for each group in table

i have following SQL table A in my database:
index, group, foo
1 A 2
2 A 2
3 A 0
4 A 1
5 B 2
6 B 1
7 C 1
There are few more groups and I need to write a query based on this filter table B. For each group in table A it's index should be equal or greater than index_egt from table B for the same group.
If the group is not listed in table B, the group won't be filtered.
index_egt, group
3 A
5 B
Expected result:
index, group, foo
3 A 0
4 A 1
5 B 2
6 B 1
7 C 1
Try this, the A.index>=B.index_egt will handle cases where the group is listed in TableB and the B.index_egt IS NULL will handle cases where the group is not listed:
SELECT
A.index,
A.group,
A.foo
FROM TableA AS A
LEFT JOIN TableB AS B ON A.group=B.group
WHERE A.index>=B.index_egt
OR B.index_egt IS NULL
select
a.*
from
A a
left join
B b ON b.group = a.group
where
a.index >= b.index_egt OR b.index_egt IS NULL
I always like this trick with coalesce
SELECT a.*
FROM a_table_with_no_name a
LEFT JOIN b_table_with_no_name b ON b.group = a.group
WHERE a.index >= COALESCE(b.index_egt,a.index)

SQL join query about dates

I have a table A as
ID Settle Date
1 1/15/2013
2 2/15/2013
and Table B as
ID From Rate
1 1/1/2013 1.5
1 2/1/2013 2
2 1/1/2013 4
2 2/1/2013 5
I want a join such that i get
ID Settle Date Rate
1 1/15/2013 1.5
2 2/15/2013 5
Basically, want to get the rate applicable for the date. Please advise
Use BETWEEN in your join:
select
a.ID
SettleDate,
Rate
FROM TableA a
INNER JOIN TableB b
ON a.SettleDate BETWEEN b.From AND b.To
AND a.ID = b.ID
OK Adjusting for your "small" change (which isn't small):
select
a.ID
SettleDate,
Rate
FROM TableA a
INNER JOIN TableB b
ON a.ID = b.ID
AND b.[From] = (SELECT MAX([From]) FROM TableB WHERE ID = a.ID AND From <= a.SettleDate)

comparing rows in sql on two different columns

id address retailer
1 A 11
2 A 11
3 A 11
4 A 12
5 A 13
6 B 12
7 B 12
8 B 13
My output should be
id address retailer
1 A 11
4 A 12
5 A 13
6 B 12
8 B 13
i.e my query should return id's which have same address but not same retailer.
How toget this?
Try to use group by clause as below:
select min(id), address, retailer
from tab
group by address, retailer
Assuming you're joining on columns with no duplicates, which is by far the most common case:
An inner join of A and B gives the result of A intersect B, i.e. the inner part of a venn diagram intersection.
An outer join of A and B gives the results of A union B, i.e. the outer parts of a venn diagram union.
Examples:
Suppose you have two Tables, with a single column each, and data as follows:
A B
- -
1 3
2 4
3 5
4 6
Note that (1,2) are unique to A, (3,4) are common, and (5,6) are unique to B.
Inner join:
An inner join using either of the equivalent queries gives the intersection of the two tables, i.e. the two rows they have in common.
select *
from a
INNER JOIN b on a.a = b.b;
select a.*,b.*
from a,b
where a.a = b.b;
a | b
--+--
3 | 3
4 | 4
Left outer join:
A left outer join will give all rows in A, plus any common rows in B.
select *
from a
LEFT OUTER JOIN b on a.a = b.b;
select a.*,b.*
from a,b
where a.a = b.b(+);
a | b
--+-----
1 | null
2 | null
3 | 3
4 | 4
Full outer join:
A full outer join will give you the union of A and B, i.e. All the rows in A and all the rows in B. If something in A doesn't have a corresponding datum in B, then the B portion is null, and vice versa.
select *
from a
FULL OUTER JOIN b on a.a = b.b;
a | b
-----+-----
1 | null
2 | null
3 | 3
4 | 4
null | 6
null | 5
select min(id) as id,address, retailer
from table1
group by address, retailer
order by id
The query you need is:
SELECT min(id), address, retailer
FROM table1 AS t1
group by address, retailer
order by address
Here's the source
Use This: It's working:
SELECT * FROM `sampletable` GROUP BY address, retailer