inner join select results with a table - sql

How to join select results with another table?
Example: generate 2-column table of aggregate value of each product type
SELECT product_type, SUM(value) AS total from table1
WHERE something_something_is_true
GROUP BY product_type;
Another table named table2 has textual descriptions of product types
product_type | description | more columns
---------------------------------------
1 | ....................
2 | ....................
How to join description column to the above selection results so that the resulting table looks something like this?
product_type | total | description
---------------------------------
1 | 589 | stationary
2 | 234 | closing

You can use a subquery as a table expression:
SELECT t1.product_type, total, description
FROM (SELECT product_type, SUM(value) AS total
FROM table1
WHERE something_something_is_true
GROUP BY product_type) t1
JOIN table2 t2 ON t1.product_type = t1.product_type

Use your query as a derived table and then join your description table to it.
select t1.*, t2.description
from (
SELECT product_type, SUM(value) AS total
from table1
WHERE ...
GROUP BY product_type
) t1
join table2 t2 on t1.product_type = t2.product_type

You can just do:
SELECT t1.product_type, SUM(value) AS total,
MAX(t2.description)
FROM table1 t1 LEFT JOIN
table2 t2
ON t2.product_type = t1.product_type
WHERE something_something_is_true
GROUP BY t1.product_type;

Related

Query to find the count of total IDs, and IDs having null in any column and the percentage of the two (i.e. Count of ID having null /total ID count)

There are two tables.
Tables A has following structure
ID
Flag
Name
1X
1
Y
2Y
0
Null
3Z
1
Null
4A
1
Y
Table B has the following structure
B_ID
City
State
1X
Y
Null
2Y
Null
Null
3Z
Null
Y
4A
Y
Y
I want to get the count of all the IDs and the count of IDs that have Null in any of the columns (name, city, state), for e.g from the tables above only the ID 4A has non null value in all the three columns across both the tables, so the output should be like
Total_Count
Ids having null
Percentage missing
4
3
0.75%
Total_count is 4 as there are total of four IDs, ID having NULL is 3 because there are 3 IDs that have null in any of the three columns (viz. name,city,state), and Percentage missing is just IDs having null / Total_Count.
I tried using a query along the following lines
select (count/total) * 100 pct, count,total
from (select sum(count) count
from(select count(*) count from tableA T1
where T1.name is null
union all
select count(*) count from tableA T1
join tableB T2 on T1.ID = T2.B_ID
where T2.city is null
union all
select count(*) count from tableA T1
join tableB T2 on T1.ID = T2.B_ID
where T2.state is null)),
select count(ID) total from tableA);
But the query is not returning the desired output, can you please suggest me a better way?
Thank You
Use conditional aggregation:
SELECT COUNT(*) Total_Count,
COUNT(CASE WHEN t1.Name IS NULL OR t2.City IS NULL OR t2.State IS NULL THEN 1 END) Ids_having_null,
AVG(CASE WHEN COALESCE(t1.Name, t2.City, t2.State) IS NOT NULL THEN 1 ELSE 0 END) Percentage_missing
FROM Table1 t1 INNER JOIN Table2 t2
ON t2.B_ID = t1.ID;
See the demo.
If you don't know if either table has all the ID's?
Then I suggest a full join with some conditional aggregation in a sub-query.
For example:
select
Total as "Total_Count"
, TotalMissing as "Ids having null"
, (TotalMissing / Total)*100||'%' as "Percentage missing"
from
(
select
count(distinct coalesce(a.ID, b.B_ID)) as Total
, count(distinct case
when a.name is null
or b.city is null
or b.state is null
then coalesce(a.ID, b.B_ID)
end) as TotalMissing
from TableA a
full outer join TableB b
on a.ID = b.B_ID
) q
Total_Count | Ids having null | Percentage missing
----------: | --------------: | :-----------------
4 | 3 | 75%
db<>fiddle here
Try this ->
select total_count, (total_count - cn) as ids_having_null,
(total_count - cn) *100 / total_count as Percentage_missing
FROM
(select count(t1.ID) as cn , t1.total_count
FROM ( select ID,Name, sum(tmp_col) over ( order by tmp_col) as total_count from (select ID,Name, 1 as tmp_col from tableA ) ) t1
JOIN TableB t2
ON t1.ID = t2.B_ID
WHERE t1.Name is not null and t2.City is not null and t2.State is not null );
Based on your requirement for percentage or ratio, you can alter the logic for Percentage_missing column

comparing sum of 2 column values in one table with another column value in second table sql server

I have two tables...
table1 ( id, item, price ) values:
id | item | price
-------------
10 | book | 20
20 | copy | 30
30 | pen | 10
....table2 ( id, item, price) values:
id | item | price
-------------
10 | book | 20
10 | book | 30
now i if do not have a record with id-10,item-book and price-(20+30) in table 1 then i want to insert that row with sum(20+30) in a new table ...
If I haven't misunderstood your requirements, this should do it:
SELECT T2.ID, T2.ITEM,T2.SUMPRICE FROM
(SELECT ID, ITEM, SUM(PRICE) AS SUMPRICE FROM table1 GROUP BY ID, ITEM) AS T1
INNER JOIN
(SELECT ID, ITEM, SUM(PRICE) AS SUMPRICE FROM table2 GROUP BY ID, ITEM) AS T2
ON T1.ID = T2.id AND T1.item = T2.item WHERE T1.SUMPRICE <> T2.SUMPRICE
If your 3rd table is already created you could just use an INSERT INTO SELECT statement. Otherwise you could use a SELECT INTO like this:
SELECT T2.ID, T2.ITEM,T2.SUMPRICE as price into table3 FROM
(SELECT ID, ITEM, SUM(PRICE) AS SUMPRICE FROM table1 GROUP BY ID, ITEM) AS
T1
INNER JOIN
(SELECT ID, ITEM, SUM(PRICE) AS SUMPRICE FROM table2 GROUP BY ID, ITEM) AS
T2
ON T1.ID = T2.id AND T1.item = T2.item WHERE T1.SUMPRICE <> T2.SUMPRICE
Hope it helps!
EDIT 1
In the case that you want to get all the unmatched rows, that is:
Rows from table 2 where the id, item or price don't match simultenously with a given row in table 1
Rows from table 2 where none of their columns match simultenously with a given row in table 1
You could use the EXCEPT statement, for example:
(SELECT ID, ITEM, SUM(PRICE) AS SUMPRICE FROM table2 GROUP BY ID, ITEM)
EXCEPT
(SELECT ID, ITEM, SUM(PRICE) AS SUMPRICE FROM table1 GROUP BY ID, ITEM)
This returns:
ID ITEM SUMPRICE
---- -------------------- -----------
10 book 50
Try the following
SELECT T2.id,T2.item,T2.Price as Table2_Price,T1.Price as Table1_Price FROM (
SELECT id,Item,Sum(Price) as Price
FROM Table2
Group BY id,Item ) AS T2 LEFT JOIN Table1 AS T1
ON T1.Item = T2.Item and T1.ID = T2.ID
After reading your comments when sum of these two not equals the one in another table it should return the sum from table 2 , you are asking for the following logic
SELECT T2.id,T2.Item, CASE WHEN T1.Price IS NULL THEN T2.Price
WHEN T2.Price <> T1.Price THEN T2.Price
ELSE T1.Price END as Price FROM (
SELECT id,Item,Sum(Price) as Price
FROM Table2
Group BY id,Item ) AS T2 LEFT JOIN Table1 AS T1
ON T1.Item = T2.Item and T1.ID = T2.ID
But this logic isn't useful, because if Sum(Table2_price) <> Table1_Price you want to select Sum(Table2_price) else when Sum(Table2_price) = Table1_Price you want Table1_Price !! So you want to always choose Sum(Table2_Price)

Join with a second table containing multiple records, take the latest

I have two tables:
person_id | name
1 name1
2 name2
3 name3
and a second table:
person_id | date | balance
1 2016-03 1200 ---- \
1 2016-04 700 ---- > same person
1 2016-05 400 ---- /
3 2016-05 4000
Considering that person_id 1 has three record on the second table how can I join the first just by taking the latest record? (that is: balance 400, corresponding to date: 2016-05).
E.g.: query output:
person_id | name | balance
1 name1 400
2 name2 ---
3 name3 4000
if it's possibile prefer the simplicity over the complexity of the solution
A query working for all DB engines is
select t1.name, t2.person_id, t2.balance
from table1 t1
join table2 t2 on t1.person_id = t2.person_id
join
(
select person_id, max(date) as mdate
from table2
group by person_id
) t3 on t2.person_id = t3.person_id and t2.date = t3.mdate
The best way to do this in any database that supports the ANSI standard window functions (which is most of them) is:
select t1.*, t2.balance
from table1 t1 left join
(select t2.*,
row_number() over (partition by person_id order by date desc) as seqnum
from table2 t2
) t2
on t1.person_id = t2.person_id and seqnum = 1;

Why my query with union operator returns only fields from first select?

I need to get all values from table and values with condition for 'not null'.
So I make two SELECT statements.
select oa.dept_id, COUNT(oa.id) quantity, sum(oa.premium) 'sum'
from Table1 oa
Left Join Table2 od On od.id = oa.dept_id
group by oa.dept_id
Union all
select oa1.dept_id, COUNT(oa1.id) quantity1, sum(oa1.premium) 'sum1'
from Table1 oa1
Left Join Table2 od1 On od1.id = oa1.dept_id
where oa1.action is not null
group by oa1.dept_id
I expect result like this with 70 rows:
-----------------------------------------------
| dept.id | quantity | sum | quantity1 | sum1 |
-----------------------------------------------
I got result like this with 130 rows:
----------------------------
| dept.id | quantity | sum |
----------------------------
You need to use join
select a.dept_id, quantity, sum,quantity1,sum1
from
(
select oa.dept_id, COUNT(oa.id) quantity, sum(oa.premium) 'sum'
from Table1 oa
Left Join Table2 od On od.id = oa.dept_id
group by oa.dept_id
) a
join
(
select oa1.dept_id, COUNT(oa1.id) quantity1, sum(oa1.premium) 'sum1'
from Table1 oa1
Left Join Table2 od1 On od1.id = oa1.dept_id
where oa1.action is not null
group by oa1.dept_id
) b
on a.dept_id=b.dept_id

SQL Query - ID Join, Just Duplicates

I am working with Oracle SQL. I have two tables. One has ItemID and DatePurchased and the other has ItemID, CustomerID. I'm trying to join the tables so that I can see only those customers with multiple items.
In other words, if I had:
TABLE 1
ItemID---DatePurchased
1 MAR15
2 JUN10
3 APR02
and
TABLE 2
ItemID---CustomerID
1 1
2 1
3 2
I would want this returned:
TABLE 3
ItemID--DatePurchased--CustomerID
1 MAR15 1
2 JUN10 1
(Customer 2 is left out because he only has one item (ItemID=3)).
Any ideas on how to do this in SQL?
select ItemID, DatePurchased, CustomerID
from
(
select
T1.ItemID, T1.DatePurchased, T2.CustomerID,
count(*) over (partition by T2.CustomerId) as ItemCnt
from TABLE2 T2
join TABLE1 T1 on T1.ItemID = T2.ItemID
) dt
where ItemCnt > 1
select
T2.ItemID, T2.CustomerID, T1.DatePurchased
from TABLE2 as T2
inner join TABLE1 as T1 on T1.ItemID = T2.ItemID
where
T2.CustomerID in
(
select TT.CustomerID
from TABLE2 as TT
group by TT.CustomerID
having count(*) > 1
)