Joining 3 columns from one table to 1 column in another table - sql

I'm trying to join Table1 to Table2 as shown below:
Table1:
| RecCurr | PayCurr | MTMCurr | TradeID |
|---------|---------|---------|---------|
| USD | CAD | JPY | 1234 |
Table2:
+------+-------+
| Curr | Value |
+------+-------+
| USD | 10 |
| CAD | 11 |
| JPY | 12 |
+------+-------+
Joined table:
+---------+---------+---------+---------+----------+----------+----------+
| RecCurr | PayCurr | MTMCurr | TradeID | RecValue | PayValue | MTMValue |
+---------+---------+---------+---------+----------+----------+----------+
| USD | CAD | JPY | 1234 | 10 | 11 | 12 |
+---------+---------+---------+---------+----------+----------+----------+
So far, the only solution I have is the following:
SELECT T1.RecCurr, T1.PayCurr, T1.MTMCurr, T2.RecValue, T3.PayValue, T4.MTMValue
FROM
(SELECT RecCurr, PayCurr, MTMCurr FROM Table1) T1,
(SELECT RecCurr, RecValue FROM Table2) T2,
(SELECT PayCurr, PayValue FROM Table2) T3,
(SELECT MTMCurr, MTMValue FROM Table2) T4
where T1.RecCurr = T2.RecCurr
and T1.PayCurr = T3.PayCurr
and T4.MTMCurr = T4.MTMCurr
Is there a cleaner solution that doesn't require me to join Table2 3 times with Table1?

NOTE: Following works on ASE; me thinks it should work on SQLAnywhere (and IQ) but I don't have a SQLAnywhere db up and running at the moment ...
If you only want to do a single join to Table2 then you'll need a query that performs a table pivot.
First the setup:
create table Table1
(RecCurr char(3)
,PayCurr char(3)
,MTMCurr char(3)
,TradeID int)
go
insert Table1 values ('USD','CAD','JPY',1234)
go
create table Table2
(Curr char(3)
,Value int)
go
insert Table2 values ('USD',10)
insert Table2 values ('CAD',11)
insert Table2 values ('JPY',12)
go
select * from Table1
go
RecCurr PayCurr MTMCurr TradeID
------- ------- ------- -----------
USD CAD JPY 1234
select * from Table2
go
Curr Value
---- -----------
USD 10
CAD 11
JPY 12
An example query with a single join to Table2:
select T1.RecCurr,
T1.PayCurr,
T1.MTMCurr,
T1.TradeID,
sum(case when T2.Curr = T1.RecCurr then T2.Value else 0 end) as RecValue,
sum(case when T2.Curr = T1.PayCurr then T2.Value else 0 end) as PayValue,
sum(case when T2.Curr = T1.MTMCurr then T2.Value else 0 end) as MTMValue
from Table1 T1,
Table2 T2
where T2.Curr in (T1.RecCurr, T1.PayCurr, T1.MTMCurr)
group by T1.RecCurr, T1.PayCurr, T1.MTMCurr, T1.TradeID
go
RecCurr PayCurr MTMCurr TradeID RecValue PayValue MTMValue
------- ------- ------- ----------- ----------- ----------- -----------
USD CAD JPY 1234 10 11 12
And for those with allergies to comma's (in the FROM clause):
select T1.RecCurr,
T1.PayCurr,
T1.MTMCurr,
T1.TradeID,
sum(case when T2.Curr = T1.RecCurr then T2.Value else 0 end) as RecValue,
sum(case when T2.Curr = T1.PayCurr then T2.Value else 0 end) as PayValue,
sum(case when T2.Curr = T1.MTMCurr then T2.Value else 0 end) as MTMValue
from Table1 T1
join Table2 T2
on T2.Curr in (T1.RecCurr, T1.PayCurr, T1.MTMCurr)
group by T1.RecCurr, T1.PayCurr, T1.MTMCurr, T1.TradeID
go
RecCurr PayCurr MTMCurr TradeID RecValue PayValue MTMValue
------- ------- ------- ----------- ----------- ----------- -----------
USD CAD JPY 1234 10 11 12

There is always a better way to write a query when it has commas in the FROM clause. In addition, the subqueries are unnecessary:
SELECT T1.RecCurr, T1.PayCurr, T1.MTMCurr,
T2r.RecValue, T2p.PayValue, T2m.MTMValue
FROM T1 JOIN
Table2 t2r
ON T2r.RecCurr = T1.RecCurr JOIN
Table2 t2p
ON t2p.PayCurr = t1.PayCurr
Table2 t2m
ON t2m.MTMCurr = t1.MTMCurr;

Related

Get only the code and total number Oracle SQL

I have 2 tables below.I want to join them
Table1
--------------
T1_id | desc
--------------
1 | test 1
2 | test 2
table2 (detail)
---------------
T2_id | Price
----------------
1 | 100000
1 | 0
1 | 0
2 | 300000
2 | 0
2 | 0
2 | 0
i want the results for this
--------------
code | total
--------------
1 | 100000
2 | 300000
this query
select a.T1_id as Code,
b.price as Total
from Table1 a
inner join table2 b on b.T2_id = a.T1_id
group by a.T1_id ,b.price;
Use below query instead to get the total price
select a.T1_id as Code,
SUM(b.price) as Total
from Table1 a
inner join table2 b on b.T2_id = a.T1_id group by a.T1_id;
Sample output:
Referring to the sample
To exclude 0 values:
SELECT T1_ID AS CODE, PRICE AS PRICE FROM TABLE1 JOIN TABLE2 ON T1_ID=T2_ID
WHERE PRICE<>0
sum of same id:
SELECT T1_ID AS CODE, SUM(PRICE) AS PRICE FROM TABLE1 JOIN TABLE2 ON T1_ID=T2_ID
GROUP BY T1_ID
I fail to see where Table 1 comes into play at all. Presumably the t2_id is a FK back to t1_id. You aren't presenting the column DESC at all, so why are you bothering to join on table_1?
So what's wrong with simply
select t2_id CODE,
sum(price) TOTAL
from table2
group by t2_id
order by t2_id
;

Replace values to different values

Please help me. I need to replace table1's code1,code2,code3 values to table2 description.
Table 1
ID CODE1 CODE2 CODE3
--------------------------
222 4wta 5qer 2qrst
223 5qer 4rstu 4tws
224 4tws 2thua 1thur
225 4tws 5qer 3wrst
Table 2
code description
-------------------
4wta Good
5qer medium
2qrst Average
1thur Mild
3wrst Progress
2thua Success
4rstu Poor
4tws Low
After Replace
ID CODE1 CODE2 CODE3
-----------------------------
222 Good medium Average
You can join table2 to table1 for each column (this will require 3 joins):
SELECT t1.id,
t2a.description AS code1,
t2b.description AS code2,
t2c.description AS code3
FROM table1 t1
INNER JOIN table2 t2a ON t1.code1 = t2a.code
INNER JOIN table2 t2b ON t1.code2 = t2b.code
INNER JOIN table2 t2c ON t1.code3 = t2c.code
Or you could unpivot table1 from columns to rows then perform a single join to table2 and then pivot the table back from rows to columns:
WITH pivoted_values ( id, name, description ) AS (
SELECT id,
name,
t2.description
FROM (
SELECT *
FROM table1
UNPIVOT ( code FOR name IN ( code1, code2, code3 ) )
) t1
INNER JOIN table2 t2 ON t1.code = t2.code
)
SELECT id,
code1,
code2,
code3
FROM pivoted_values
PIVOT (
MAX( description )
FOR name IN (
'CODE1' AS code1,
'CODE2' AS code2,
'CODE3' AS code3
)
)
Both of them output:
ID | CODE1 | CODE2 | CODE3
--: | :----- | :------ | :-------
222 | Good | medium | Average
223 | medium | Poor | Low
224 | Low | Success | Mild
225 | Low | medium | Progress
db<>fiddle here

SQL - find records from one table which exist in another and delete if not

I've got the following four SQL tables:
Table 1:
-----------------------
Product | Date_Purchase
-----------------------
abc | 06-Jan-19
def | 05-Jan-18
ghi | 05-Apr-19
abc | 06-Feb-19
Table 2:
------------------------
Product | Date_Purchase
------------------------
jkl | 6-Feb-19
mno | 2-Aug-18
ghi | 9-May-19
pqr | 1-Sep-19
Table 3:
-------------------------
Product | Date_Purchase
-------------------------
ghi | 2-Aug-18
mno | 9-May-19
pqr | 2-Aug-18
abc | 06-Jan-19
Table 4:
-------------------------
Product | Date_Purchase
-------------------------
stu | 9-May-19
vwx | 05-Apr-19
ghi | 9-May-19
def | 05-Jan-18
I've got the below code which joins the tables with Union:
SELECT Product, Date_Purchase FROM Table1 UNION ALL
SELECT Product, Date_Purchase FROM Table2 UNION ALL
SELECT Product, Date_Purchase FROM Table3 UNION ALL SELECT Product, Date_Purchase FROM Table4
ORDER BY Product, Date_Purchase;
I would like to delete all the rows from the tables, no matter the table, that appear only once in all the tables.
For example jkl, stu and vwx appear only once, so I would like to delete the entire rows from the table where they appear. Does anyone have any idea how to do that?
Also how could i delete all the products that appear in the tables and have the same purchase date?
A solution for MySql with which in 1 statement you can delete from all 4 tables:
delete t1, t2, t3, t4
from (
select u.product, count(*) counter
from (
select * from table1 union all
select * from table2 union all
select * from table3 union all
select * from table4
) u
group by u.product
) t
left join table1 t1 on t1.product = t.product
left join table2 t2 on t2.product = t.product
left join table3 t3 on t3.product = t.product
left join table4 t4 on t4.product = t.product
where t.counter = 1;
See the demo.
Results:
Table1
> Product | Date_Purchase
> :------ | :------------
> abc | 06-Jan-19
> def | 05-Jan-18
> ghi | 05-Apr-19
> abc | 06-Feb-19
Table2
> Product | Date_Purchase
> :------ | :------------
> mno | 2-Aug-18
> ghi | 9-May-19
> pqr | 1-Sep-19
Table3
> Product | Date_Purchase
> :------ | :------------
> ghi | 2-Aug-18
> mno | 9-May-19
> pqr | 2-Aug-18
> abc | 06-Jan-19
Table4
> Product | Date_Purchase
> :------ | :------------
> ghi | 9-May-19
> def | 05-Jan-18
If "delete" means not returning return them in a select, then:
SELECT pd.*
FROM (SELECT pd.*, COUNT(*) OVER (PARTITION BY Product) as cnt
FROM ((SELECT Product, Date_Purchase FROM Table1
) UNION ALL
(SELECT Product, Date_Purchase FROM Table2
) UNION ALL
(SELECT Product, Date_Purchase FROM Table3
) UNION ALL
(SELECT Product, Date_Purchase FROM Table4
)
) pd
) pd
WHERE cnt = 1;
If "delete" means, delete, then you need four delete statements, each like this:
delete t
from table1 t
where not exists (select 1 from table2 where t2.product = t.product) and
not exists (select 1 from table3 where t3.product = t.product) and
not exists (select 1 from table4 where t4.product = t.product);
Actually, this delete products that are only in on table, even if they are there multiple times. It can be tweaked to only delete the singletons, if that is also necessary.
To give it a try for Scratte‘s version of only if product and Date occurs twice (unchecked because written on mobile device):
SELECT pdo.*
FROM (SELECT pd.*, COUNT(*) OVER (PARTITION BY Product) as cnt
FROM ((SELECT Product, Date_Purchase FROM Table1
) UNION ALL
(SELECT Product, Date_Purchase FROM Table2
) UNION ALL
(SELECT Product, Date_Purchase FROM Table3
) UNION ALL
(SELECT Product, Date_Purchase FROM Table4
)
) pd
) pdo
Group by pdo.Product,pdo.Date_Purchase
Having cnt=1

Joining rows from two tables

I have two tables Table1 and Table2. I wanted to join the two tables data based on the TIME_STAMP data field
I have tried the below query but I am not able to get the expected result
Table 1
CATEGORY_ID ID TIME_STAMP VALUE
-------------------------------------
1 444 30-Mar-17 XXX
1 444 31-Jul-18 YYY
1 444 15-Jan-19 ZZZ
Table 2
CATEGORY_ID ID TIME_STAMP VALUE
------------------------------------------
2 444 30-Mar-17 10/31/2017
2 444 30-May-18 10/25/2018
2 444 13-Jun-19 10/25/2018
Actual Result:
TIME_STAMP Table 1 VALUE Table 2 value
-------------------------------------------
30-Mar-17 XXX 10/31/2017
31-Jul-18 YYY NULL
15-Jan-19 ZZZ NULL
Query :
SELECT
T1.TIME_STAMP ,
T1.X_VALUE,
T2.X_VALUE
FROM
TABLE1 T1
LEFT OUTER JOIN TABLE2 T2 ON T1.ID = T2.ID
AND
TO_CHAR(T1.TIME_STAMP,'MM/DD/YYYY')
=TO_CHAR(T2.TIME_STAMP,'MM/DD/YYYY')
AND
T2.CATEGORY_ID=2
WHERE
T1.CATEGORY_ID =1 AND T1.ID= 444
Expected Result:
TIME_STAMP Table1 VALUE Table2 VALUE
-----------------------------------------
30-Mar-17 XXX 10/31/2017
30-May-18 NULL 10/25/2018
31-Jul-18 YYY NULL
15-Jan-19 ZZZ NULL
13-Jun-19 NULL 10/25/2018
FULL OUTER JOIN with filtering is tricky. I recommend using a subquery for the filtering criteria:
select coalesce(t1.time_stamp, t2.time_stamp) as time_stamp,
t1.x_value, t2.x_value
from (select t1.*
from table1 t1
where t1.CATEGORY_ID = 1 and T1.ID = 444
) t1 full join
(select t2.*
from table2 t2
where t2.id = 444 and t2.category_id = 2
) t2
on t2.id = t1.id and
trunc(t2.time_stamp) = trunc(t1.time_stamp);
Based on your expected result I think you want to do a FULL OUTER JOIN on the TIME_STAMP column.
You could do something like this.
SELECT COALESCE(t1.time_stamp, t2.time_stamp) AS TIME_STAMP,
t1.value as T1_value,
t2.value as T2_value
FROM table01 t1
FULL OUTER JOIN table02 t2 ON t1.time_stamp = t2.time_stamp
+-------------+-----------+------------+
| TIME_STAMP | T1_value | T2_value |
+-------------+-----------+------------+
| 2017-03-30 | XXX | 10/31/2017 |
| 2018-07-31 | YYY | (null) |
| 2019-01-15 | ZZZ | (null) |
| 2018-05-30 | (null) | 10/25/2018 |
| 2019-06-13 | (null) | 10/25/2018 |
+-------------+-----------+------------+
Note: I have used SQL Server since you haven't mentioned a DBMS.
before you join the two tables with timestamp, you need trunc the timestamp to Date.
like TRUNC("TimeStamp", DATE)
SELECT COALESCE(t1.time_stamp, t2.time_stamp) AS TIME_STAMP,
t1.value as T1_value,
t2.value as T2_value
FROM table01 t1
FULL OUTER JOIN table02 t2
ON trunc(t1.time_stamp, 'DATE') = trunc(t2.time_stamp, 'DATE');

Getting all the current effective records from a ORACLE table

I have two tables in oracle database
Table 1 say table1 with fields (id, name)
Records e.g.
###############
id | name
1 | Chair
2 | Table
3 | Bed
###############
and Table 2 say table2 with fields (id, table1_id, date, price)
##############################
id |table1_id| date | price
1 | 1 | 2013-09-09 | 500
2 | 1 | 2013-08-09 | 300
3 | 2 | 2013-09-09 | 5100
4 | 2 | 2013-08-09 | 5000
5 | 3 | 2013-09-09 | 10500
################################
What I want to achieve is to retrieve all the latest price of items from table 2
Result of SQL should be like
##############################
id |table1_id| date | price
1 | 1 | 2013-09-09 | 500
3 | 2 | 2013-09-09 | 5100
5 | 3 | 2013-09-09 | 10500
################################
I am able to run in mysql by following query
SELECT t2.id, t1.id, t1.name, t2.date, t2.price
FROM table1 t1 JOIN table2 t2
ON (t1.id = t2.table1_id
AND t2.id = (
SELECT id
FROM table2
WHERE table1_id = t1.id
ORDER BY table2.date DESC
LIMIT 1
));
but it's not working in ORACLE, Here i Need a query which can run on both server with minor modification
You may try this (shoud work in both MySQL and Oracle):
select t2.id, t2.table1_id, t2.dat, t2.price
from table1 t1 join table2 t2 on (t1.id = t2.table1_id)
join (select table1_id, max(dat) max_date
from table2 group by table1_id) tmax
on (tmax.table1_id = t2.table1_id and tmax.max_date = t2.dat);
This query may return several rows for the same table1_id and date if there are several prices in table2, like this:
##############################
id |table1_id| date | price
1 | 1 | 2013-09-09 | 500
2 | 1 | 2013-09-09 | 300
It's possible to change the query to retrieve only 1 row for each table1_id, but there should be some additional requirements (which row to choose in the above example)
if it doesn't matter then you may try this:
select max(t2.id) as id, t2.table1_id, t2.dat, max(t2.price) as price
from table1 t1 join table2 t2 on (t1.id = t2.table1_id)
join (select table1_id, max(dat) max_date
from table2 group by table1_id) tmax
on (tmax.table1_id = t2.table1_id and tmax.max_date = t2.dat)
group by t2.table1_id, t2.dat;
You can try this using GROUP BY instead, since you're not retrieving the product name from table1 except the product id (which is already in table2)
SELECT id,table1_id,max(date),price
FROM table2
GROUP BY id,table1_id,price
this is what you want :
select t2.id,t2.table1_id,t1.name,t2.pricedate,t2.price
from table1 t1
join
(
select id,table1_id, pricedate,price, row_number() over (partition by table1_id order by pricedate desc) rn
from table2
) t2
on t1.id = t2.table1_id
where t2.rn = 1