I'm looking for a way to solve my SQL problem.
I have 2 tables in Firebird 2.5 ( T1 and T2 ) like these:
T1 (
T1_ID INTEGER,
T1_DAY DATE,
T1_NAME VARCHAR(200)
)
T2 (
T2_ID INTEGER,
T2_DAY DATE,
T2_NAME VARCHAR(200)
)
I need a query that mixes records of those tables and sort them in ascending date order. I don't care if a join query increases the number of fields or the date field is not the same as result or stored procedures are needed.
Example output
T1_ID T1_DAY T1_NAME T2_ID T2_DAY T2_NAME
---------------------------------------------------
1 01/02/2011 BOB NULL NULL NULL
2 27/02/2011 SAM NULL NULL NULL
NULL NULL NULL 8 15/03/2011 PETER
NULL NULL NULL 10 21/03/2011 JOHN
6 17/04/2011 AMY NULL NULL NULL
or (better output)
ID DAY NAME
-------------------------
1 01/02/2011 BOB
2 27/02/2011 SAM
8 15/03/2011 PETER
10 21/03/2011 JOHN
6 17/04/2011 AMY
You want the UNION operator:
SELECT
T1.T1_ID ID,
T1.T1_DAY DAY,
T1.T1_NAME NAME
FROM
T1
UNION
SELECT
T2.T2_ID,
T2.T2_DAY
T2.T2_NAME
FROM
T2
;
You can make the individual selects have any additional features you like. The only restriction is that all of the columns in both of the select lists are in the same order and have the same type (they are "union compatible"). The resulting rows will have column headings like the first select.
edit: To control the ordering of a union, you'll have to do the union in a subselect and the ordering in the outer query.
SELECT u.ID, u.DAY, u.NAME
FROM (
SELECT T1.T1_ID ID, T1.T1_DAY DAY, T1.T1_NAME NAME
FROM T1
UNION
SELECT T2.T2_ID, T2.T2_DAY T2.T2_NAME
FROM T2
) u
ORDER BY u.NAME;
Related
I have two tables
T1:
ID
Reference
Status
Event Timestamp
1
Flowers
Dispatched
2021-12-10
2
Flowers
Delivered
2021-12-11
And T2:
ID
Reference
Comments
Event Timestamp
1
Flowers
well done
2021-12-12
2
Flowers
go on
2021-12-13
3
Pot
random
2021-12-13
The table I'm trying to have by querying for Flowers reference is (using Postgres)
t1_ID
t2_ID
Reference
Comments
Status
t1_Event Timestamp
t2_Event Timestamp
1
null
Flowers
null
Dispatched
2021-12-10
null
2
null
Flowers
null
Delivered
2021-12-11
null
null
1
Flowers
well done
Delivered
2021-12-11
2021-12-12
null
2
Flowers
go on
Delivered
2021-12-11
2021-12-13
In other words, I need to have a joined table that records all the update between the two tables.
I tried many queries, like LEFT JOIN, UNION, etc. however all attempts are unsuccessful.
Could you suggest me which SQL statements should I use to obtain the expected result?
Use cte and union
with cte as(
select ID as t1_ID,
null as t2_ID,
Reference,
null as Comments,
Status,
Event_Timestamp as t1_Event_Timestamp,
null as t2_Event_Timestamp,
row_number() over(partition by Reference order by Reference) seq
from t1
)
select t1_id,t2_id,reference,comments,status,t1_event_timestamp,t2_event_timestamp
from cte
union all
select null as t1_ID,
t2.ID::varchar(10) as t2_ID,
t2.Reference,
Comments,
(select max(Status) from cte t3 where t3.seq = (select max(seq) from cte)) as status,
(select max(t1_Event_Timestamp) from cte t3 where t3.Reference = t2.Reference) as t1_Event_Timestamp,
t2.Event_Timestamp as t2_Event_Timestamp
from t1
left join t2 on t1.Reference = t2.Reference
group by t2.ID,t2.Reference,t2.Comments,t2.Event_Timestamp
Demo in db<>fiddle
I am trying to get all id, std_name from table1, and all id, score from table2 where std_id of table2 matches the id of table1 and deleted_at should be null for all entries of table1 and table2. But table2 can have duplicate std_ids, in that case, I only want the entries with the maximum id number from table2.
Sample table1:
id
std_name
deleted_at
1
jhon
null
2
sam
null
3
joe
null
Sample table2:
id
std_id
score
deleted_at
1
1
10
null
2
2
20
null
3
1
30
null
So far I have tried using this query:
const query = knex.select([
't1.id as t1id',
't1.std_name as name',
't2.score as score'
])
.from('table1 as t1')
.leftJoin('table2 as t2', function () {
this.on('t2.std_id', '=', 't1.id')
})
.joinRaw('left join (select MAX(id) as id, std_id from table2 group by std_id) as kst on kst.std_id = t2.std_id');
query.where({'t1.deleted_at': null}).orderBy('t1.id')
Results generated for the above query:
id
name
score
1
jhon
30
2
sam
20
But this only returns the maximum id entry of the duplicate entries from table2 and omits the entries of table1, but I also want the ids from table1 which are not included in the std_id of table2.
My desired output:
id
name
score
1
jhon
30
2
sam
20
3
joe
null
You can use window functions. In SQL this looks like:
select t1.*, t2.score
from table1 t1 left join
(select t2.*,
row_number() over (partition by t2.std_id order by t2.id desc) as seqnum
from table2 t2
) t2
on t2.std_id = t1.id and t2.seqnum = 1;
I've a table with users by structure like this:
id name parent_id
1 Mike
2 Jack 1
3 Sam 1
4 Kurt 1
5 Somebody 3
6 Tommy 4
6 etc.. 2
How to get a max count of referral on first level nesting per user, by this example I expect result:
3 because Jack, Sam, Kurt is a referral of Mike on first level
Assuming "first level" is defined by parent_id IS NULL and the current version Postgres 9.4:
SELECT parent_id, count(*) AS referral_ct
FROM (
SELECT id AS parent_id
FROM tbl
WHERE t1.parent_id IS NULL
) t1
JOIN tbl t2 USING (parent_id)
GROUP BY 1
ORDER BY 2 DESC
LIMIT 1; -- to only get 1 row with max. referral_ct
With only few root nodes, JOIN LATERAL may be faster:
SELECT t1.id, t2.referral_ct
FROM (
SELECT id
FROM tbl
WHERE parent_id IS NULL
) t1
LEFT JOIN LATERAL (
SELECT parent_id, count(*) AS referral_ct
FROM tbl
WHERE parent_id = t1.id
GROUP BY 1
) t2 ON true
ORDER BY 2 DESC
LIMIT 1; -- to only get 1 row with max. referral_ct
Related, with more explanation:
Optimize GROUP BY query to retrieve latest record per user
I have following senario
table1 - having 1 record with 1001(primary key)
table2 - having 3 record with same id (1001) - not as primary key
table3 - having 3 record with same id (1001) - not as primary key
The join of the first 2 tables is returning 3 rows (it is fine). But, if I join table3 then it is returning 9 rows. I know how join work and result is expected.
I need only 3 rows in result. something like shown below
id name age sex city
1001 Jhon 20 A Z
1001 Jhon 20 B Y
1001 Jhon 20 C X
Here is fiddle example
This query may do what you ask for. To change the combination between Table2 and Table3 you can work on the two ORDER BY clauses. Really strange requierement anyway! Are you sure you're doing it right?
with ord_t2 as (
select idt1 as id, sex, row_number() over(partition by idt1 order by sex) as ord_no
from table2 t2
), ord_t3 as (
select idt3 as id, city, row_number() over(partition by idt3 order by city) as ord_no
from table3 t3
), t2_x_t3 as (
select id, sex, city
from ord_t2
natural full outer join ord_t3
)
select *
from Table1
natural left join t2_x_t3
I have this table:
| id | Reader id | Book id | Taken date | Return date |
And, for example, 3 rows
id Reader_id Book_id Taken_date Return_date
1 1 1 1999-01-08 NULL
2 2 2 2015-03-09 2015-04-10
3 1 3 2013-01-01 2014-01-01
I need to get the id's of the readers who have returned books, so all the rows with that id in this table need to have Return_date != NULL. In the case above the query is supposed to return only the second row and not return the last row, because the reader from the last row has not returned a book. How to achieve that?
First identify the Reader_id who has to return books
SELECT Reader_id
FROM yourtable
WHERE Return_date IS NULL
Then select the readers from which is not present in above query result
Use NOT IN
SELECT *
FROM yourtable
WHERE Reader_id NOT IN (SELECT Reader_id
FROM yourtable
WHERE Return_date IS NULL)
Or use Not Exists which can handle NULL values from Sub-Query
SELECT *
FROM yourtable a
WHERE NOT EXISTS (SELECT 1
FROM yourtable b
WHERE b.Return_date IS NULL
AND a.Reader_id = b.Reader_id)
You can do this with a left join :
SELECT * FROM YourTable t
LEFT OUTER JOIN YourTable s
ON(t.reader_id = s.reader_id
and s.id <> t.id
and s.Return_date is null)
WHERE s.id is null
AND t.Return_date is not null
Try this...
select
reader_id
from
tablename
where id not in (SELECT id
FROM tablename
WHERE Return_date IS NULL)