Joining rows from two tables - sql

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');

Related

Take data from two tables and show in one row without duplicates with a where condition

I want to take the data from two tables and output them in one row .
output will have two columns "to" and "from" where the condition is "from" will be having data from second table where type is true and "to" column will have data from second table where type is false . FK_ID in second table is linked to ID on the first table . Please help with the query.
I was trying to do with inner joins and union was not able to make it work . Thanks in advance .
TABLE 1
ID | PATH|
1 | ABC |
2 | EFG |
TABLE 2
ID | FK_ID | NUMBER | TYPE
20 | 1 | 123 | TRUE
21 | 1 | 456 | FALSE
28 | 2 | 888 | FALSE
29 | 2 | 939 | TRUE
OUTPUT SHOULD BE:
ID | PATH | TO | FROM
1 | ABC | 456 | 123
2 | EFG | 888 | 939
Use aggregation with pivoting logic to identify the "to" and "from" components of each path:
SELECT
t1.ID,
t1.PATH,
MAX(CASE WHEN t2.TYPE = 'FALSE' THEN t2.NUMBER END) AS "TO",
MAX(CASE WHEN t2.TYPE = 'TRUE' THEN t2.NUMBER END) AS "FROM"
FROM table1 t1
LEFT JOIN table2 t2
ON t1.ID = t2.FK_ID
GROUP BY
t1.ID,
t1.PATH
ORDER BY
t1.ID;
If performance is an issue, you might find a lateral join to be faster:
SELECT t1.*, t2.*
FROM table1 t1 LEFT JOIN LATERAL
(SELECT SUM(T2.NUMBER) FILTER (WHERE NOT t2.TYPE) as num_to,
SUM(T2.NUMBER) FILTER (WHERE t2.TYPE) as num_from
FROM table2 t2
WHERE t1.ID = t2.FK_ID
) t2
ORDER BY t1.ID;
This avoids the outer GROUP BY and probably the sorting as well (assuming that ID is the primary key).
It also assumes that TYPE is a Postgres boolean type. If not, use string comparisons for the WHERE clauses.

Joining two tables at max date where conditions occur

I have two tables,
[TABLE_1]
| ID1 | ID2 | ID3 |
|-----+-----+-----|
| 200 | 125 | 300 |
| 206 | 128 | 650 |
| 230 | 543 | 989 |
[TABLE_2]
| ID1 | ID2 | ID3 | Date |
|-----+-----+-----+--------|
| 200 | 125 | 300 | 1/1/18 |
| 200 | 125 | 300 | 1/1/19 |
| 206 | 128 | 650 | 1/1/13 |
| 206 | 128 | 650 | 1/2/13 |
| 206 | 128 | 650 | 9/5/05 |
I'm trying to Left Join TABLE_1 to TABLE_2 while filtering the output so only rows where Date is at its maximum for those classifications are displayed. I simplified the data in my tables a little bit, but there's NO overall max date that can be used for all items in the table, the max date is unique to each item.
Desired results on the above example would be:
| ID1 | ID2 | ID3 | Date |
|-----+-----+-----+--------|
| 200 | 125 | 300 | 1/1/19 |
| 206 | 128 | 650 | 1/2/13 |
Here's my latest attempt at the query. It seems a little too complicated as I'm relatively new with SQL and has been running without giving a result for a long time now so I'm afraid it may be in an endless loop somehow:
SELECT DISTINCT *
FROM TABLE_1 t1
LEFT JOIN TABLE_2 t2
ON t1.ID1 = t2.ID1
AND t1.ID2 = t2.ID2
AND t1.ID3 = t2.ID3
WHERE t2.Date = (SELECT MAX(Date) FROM Table_2
WHERE t1.ID1 = t2.ID2
AND t1.ID2 = t2.ID2
AND t1.ID3 = t2.ID3);
Any help on how better to query this will be greatly appreciated, thanks!
Notes: The column names are not identical (I know this would cause an error), I only labeled them like that for simplification.
For your given results, why not just aggregate table 2?
select id1, id2, id3, max(date)
from table2
group by id1, id2, id3;
If you need to filter this only for the triples in table1, then:
select t2.id1, t2.id2, t2.id3, max(t2.date)
from table2 t2 join
table1 t1
on t2.id1 = t1.id1 and t2.id2 = t1.id2 and t2.id3 = t1.id3
group by t2.id1, t2.id2, t2.id3;
So as per the comments, I think the following is the complete code:
SELECT
T1.ID1,
T1.ID2,
T1.ID3,
MAX(T2.DATE) AS DATE
FROM
TABLE1 T1
-- USED LEFT JOIN AS NOT SURE IF THERE IS ATLEAST ONE ROW IN T2 FOR EACH ROW IN T1
LEFT JOIN (
SELECT
ID1,
ID2,
ID3,
MAX(DATE)
FROM
TABLE2
GROUP BY
ID1,
ID2,
ID3
) T2 ON T2.ID1 = T1.ID1
AND T2.ID2 = T1.ID2
AND T2.ID3 = T1.ID3;
Cheers!!
You can also use the WITH statement, preaggregating the entries in table 2:
WITH agg_table_2 AS (
SELECT
ID1
,ID2
,ID3
,MAX(DATE) AS MAX_DATE
FROM TABLE_2
GROUP BY
ID1
,ID2
,ID3
)
SELECT
T1.ID1
,T1.ID2
,T1.ID3
,T2.MAX_DATE
FROM TABLE_1 T1
--LEFT
JOIN TABLE_2 T2
ON T1.ID1 = T2.ID1
AND T1.ID2 = T2.ID2
AND T1.ID3 = T2.ID3
;
Note that I actually commented out the LEFT in JOIN as in your desired output 230, 543, 989 was not present. Uncomment it, if you want to keep that entry with NULL value assigned.

How can I check multiple line for one customer with SQL?

I have a table like this:
id | START_DATE | END_DATE | id_customer
----------------------------------------
1 | 01/05/2016 | 31/05/2016 | 1234
2 | 10/10/2016 | 11/11/2016 | 1234
3 | 11/11/2016 | 15/05/2017 | 1234
4 | 31/12/2016 | 31/06/2017 | 1234
I want select if a START_DATE equal a END_DATE.
For example:
11/11/2016 line id 3 don't equal 31/05/2016 line id 1
11/11/2016 line id 3 equal 11/11/2016 line id 2
11/11/2016 line id 3 don't equal 15/05/2017 line id 3
11/11/2016 line id 3 don't equal 31/06/2017 line id 4
I have try a request like this
SELECT id_cutsomer,START_DATE, END_DATE
FROM TABLE
WHERE START_DATE IN (
SELECT END_DATE FROM DATA_BEAUTY_BOX
)
I want this result:
START_DATE | END_DATE | id_customer
------------------------------------
11/11/2016 | 11/11/2016 | 1234
Can you help me ?
Thanks in advance
I think a self join should suffice
select t1.START_DATE, t2.END_DATE, t1.ID_CUSTOMER
from yourTable t1
join yourTable t2
on t1.START_DATE = t2.END_DATE
If you don't want to mix dates of different customers, you will have to make the join condition stricter
select t1.START_DATE, t2.END_DATE, t1.ID_CUSTOMER
from yourTable t1
join yourTable t2
on t1.START_DATE = t2.END_DATE and
t1.ID_CUSTOMER = t2.ID_CUSTOMER
I would join the tables on Customer ID and then Add the (Start Date = End Date) condition on the WHERE clause. (although you could do them both on the JOIN)
SELECT t1.START_DATE, t2.END_Date, t1.id_customer
FROM MyTable t1
INNER JOIN MyTable t2
ON t1.id_customer = t2.id_customer
WHERE t1.START_DATE = t2.END_Date

Query that countes pairs with same values depending on third column

I have three columns: Team_Code, ID, times_together.
I'm trying to count how many times ID's have the same "Team_Code" and add times_together to it.
In other words- I'm trying to write all the pairs of one column, check how many times they have the same value in other raw, and add third raw to it.
The simple way to ask this question is picture so:
Values can appear twice (for example
1110 with 8888
and then
8888 with 1110).
You could self join the table on team_code and sum the times_together:
SELECT t1.id, t2.id, SUM(t1.times_together)
FROM mytable t1
JOIN mytable t2 ON t1.team_code = t2.team_code AND t1.id != t2.id
If you want to make sure each pair only appears once, you could add a condition to always take the lower id on the left:
SELECT t1.id, t2.id, SUM(t1.times_together)
FROM mytable t1
JOIN mytable t2 ON t1.team_code = t2.team_code AND t1.id < t2.id
I would suggest this self-joining SQL which takes all possible ID pairs (but only where the first is smaller than the second), and uses a CASE to sum the times_together when the persons played in the same team:
select t1.id,
t2.id,
sum(case when t1.Team_Code = t2.Team_Code
then t1.times_together
else 0
end) times_together
from t as t1
inner join t as t2
on t1.id < t2.id
group by t1.id, t2.id
order by 1, 2
Output in the example case is:
| id | id | times_together |
|------|------|----------------|
| 1028 | 1110 | 0 |
| 1028 | 2220 | 0 |
| 1028 | 8888 | 0 |
| 1110 | 2220 | 1 |
| 1110 | 8888 | 1 |
| 2220 | 8888 | 6 |

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