Rajat kashyap
Rajat kashyap

Reputation: 622

How join statements execute in sql

I'm trying to fetch the data from user table such that every row contains date value(not null). If value is null then it should be view that column with a date of id of above date which have same id. Without updating the table rows, only with select statement?

Here is the table

NAME, DATE, ID
A, 2021-01-21, 1
B, null, 1
C, null, 1
D, 2021-01-18, 2
D, null, 2

It should be viewed like

A, 2021-01-21, 1
B, 2021-01-21, 1
C, 2021-01-21, 1
D, 2021-01-18, 2
D, 2021-01-18, 2

Now the query I think is =>

select t1.name, t2.date ,t1.id from user t1 
left join (select id ,date from user where id=1) t2 
on t1.id=t2.id;

But this query doesn't work like I thought.

Can anyone please tell me how above join query works ? And how can I improve it ? So that I got the required result.

For testing of above query use this queries =>

create table user(
 name varchar(20),
 date date,
 id integer
);
insert into user values("A",'2021-01-21',1);
insert into user values("",null,1);
insert into user values("",null,1);
insert into user values("",null,1);
insert into user values("",null,1);
insert into user values("",null,1);
insert into user values("B",'2021-01-20',2);

select t1.name, t2.date ,t1.id from user t1 
left join (select id ,date from user where id=1) t2 
on t1.id=t2.id;

Upvotes: 0

Views: 164

Answers (2)

Gordon Linoff
Gordon Linoff

Reputation: 1269873

You don't need a join. Just use a window function:

select name,
       max(date) over (partition by id) as date,
       id
from users;

Note that your sample data doesn't match the data in the question. That data suggests:

select max(name) over (partition by id) as name,
       max(date) over (partition by id) as date,
       id
from user;

Here is a db<>fiddle.

Upvotes: 1

Booboo
Booboo

Reputation: 44128

The first problem is that you are joining a table with itself on the condition t1.id = t2.id. So if you have 4 rows with id=1 and 3 rows with id=2 just as an example, you will end up with a result that had 4 * 4 + 3 * 3 = 25 rows. In your specific case you will end up with 6 * 6 + 1 * 1 = 37 rows.

The second problem is that you have hard-code selecting id=1 in your subquery:

(select id ,date from user where id=1) t2

This can't be the appropriate value for all possible rows.

You could try the obvious:

select
   t1.name,
   ifnull(t1.date, (select t2.date from user t2 where t2.date is not null and t2.id = t1.id limit 1)) as date,
   t1.id
from user t1
;

see db-fiddle

name id date
A 1 2021-01-21
1 2021-01-21
1 2021-01-21
1 2021-01-21
1 2021-01-21
1 2021-01-21
B 2 2021-01-20

But better would be to use a join:

select u.name, ifnull(u.date, sq.date) as date, u.id
from user u join (
    select id, min(date) as date from user group by id
) sq on u.id = sq.id
;

see db-fiddle

I would expect the second version using a join to be more efficient because the first version has a dependent subquery that has to get executed for every row that has a null date.

Upvotes: 1

Related Questions