I have two tables, linked with an outer join. The relationship between the primary and secondary table is a 1 to [0..n]. The secondary table includes a timestamp column indicating when the record was added. I only want to retrieve the most recent record of the secondary table for each row in the primary. I have to use a group by on the primary table due to other tables also part of the SELECT. There's no way to use a 'having' clause though since this secondary table is not part of the group.
How can I do this without doing multiple queries?
For performance, try to touch the table least times
Option 1, OUTER APPLY
SELECT *
FROM
table1 a
OUTER APPY
(SELECT TOP 1 TimeStamp FROM table2 b
WHERE a.somekey = b.somekey ORDER BY TimeStamp DESC) x
Option 2, Aggregate
SELECT *
FROM
table1 a
LEFT JOIN
(SELECT MAX(TimeStamp) AS maxTs, somekey FROM table2
GROUP BY somekey) x ON a.somekey = x.somekey
Note: each table is mentioned once, no correlated subqueries
Something like:
SELECT a.id, b.*
FROM table1 a
INNER JOIN table2 b ON b.parentid = a.id
WHERE b.timestamp = (SELECT MAX(timestamp) FROM table2 c WHERE c.parentid = a.id)
Use LEFT JOIN instead of INNER JOIN if you want to show rows for IDs in table1 without any matches in table2.
select *
from table1 left outer join table2 a on
table1.id = a.table1_id
where
not exists (select 1 from table2 b where a.table1_id = b.table1_id and b.timestamp > a.timestamp)
The quickest way I know of is this:
SELECT
A.*,
B.SomeField
FROM
Table1 A
INNER JOIN (
SELECT
B1.A_ID,
B1.SomeField
FROM
Table2 B1
LEFT JOIN Table2 B2 ON (B1.A_ID=B2.A_ID) AND (B1.TimeStmp < B2.TimeStmp)
WHERE
B2.A_ID IS NULL
) B ON B.A_ID = A.ID
Related
The condition is I know the right table does not have all matching records with the left table.
but I am still not able to get data from left table with null from right table
select a.sales, b.profit
from T1 a
left join T2 b on a.id = b.id
where b.category = 'office'
and b.code = '245'
because of the where condition of right table, the right table does not have matching records,
without where condition I got the records.
My question is will left table be affected with where condition of right table although using left join to retain the left table records.
Your WHERE clause forces the query to only return rows which b.category and b.code match the required values and so are non-NULL; this effectively turns your JOIN condition into an INNER JOIN.
You want to put the filters in the join condition:
select a.sales,
b.profit
from T1 a
left join T2 b
on ( a.id = b.id
AND b.category = 'office'
AND b.code = '245')
Or to pre-filter T2 in a sub-query:
select a.sales,
b.profit
from T1 a
left join (
SELECT *
FROM T2
WHERE category = 'office'
AND code = '245'
) b
on a.id = b.id
I am joining several tables. From the joined table I need to select a record with the minimum value in one column. The where clause contains some additional conditions. How can this be achieved without having to list the whole join twice in the select and in the where clause to identify the minimum?
I mean - from the result of the join, I need to select one record that fullfills some conditions and that also includes a minimum in a specific column. It is in Teradata but I am asking about the general principle.
I have something like this. It works, but is ugly as the join is included twice.
SELECT TABLE1.X, TABLE2.Y, TABLE3.Z
FROM TABLE1
INNER JOIN TABLE2
ON TABLE1.A = TABLE2.B
INNER JOIN TABLE3
ON TABLE2.C=TABLE3.D
WHERE TABLE3.M =
(SELECT MIN(TABLE3.M)
FROM TABLE1
INNER JOIN TABLE2
ON TABLE1.A = TABLE2.B
INNER JOIN TABLE3
ON TABLE2.C=TABLE3.D
WHERE TABLE1.K=123 AND TABLE2.L=456
)
Thanks, R.
In a comment you say you only need one row as your output.
In which case, use ORDER BY and LIMIT 1
SELECT TABLE1.X, TABLE2.Y, TABLE3.Z
FROM TABLE1
INNER JOIN TABLE2
ON TABLE1.A = TABLE2.B
INNER JOIN TABLE3
ON TABLE2.C=TABLE3.D
WHERE TABLE1.K=123 AND TABLE2.L=456
ORDER BY TABLE3.M
LIMIT 1
Edit: (To use min() to fulfil unstated requirements...)
SELECT
X, Y, Z
FROM
(
SELECT
TABLE1.X,
TABLE2.Y,
TABLE3.Z,
TABLE3.M,
MIN(TABLE3.M) OVER () AS MIN_M
FROM
TABLE1
INNER JOIN
TABLE2
ON TABLE1.A = TABLE2.B
INNER JOIN
TABLE3
ON TABLE2.C = TABLE3.D
WHERE
TABLE1.K = 123
AND TABLE2.L = 456
)
AS FILTERED
WHERE
MIN_M = M
Even if I was going to use window functions for this, I'd use ROW_NUMBER() OR RANK() rather than using MIN(). Without a clear reason WHY you feel this MUST use it, yet still be DRY, efficient and maintainable, this constraint appears not only pointless, but misguided.
Use min window function as follows:
Select x, y, z from
(SELECT TABLE1.X, TABLE2.Y, TABLE3.Z,
Min(TABLE3.M) over () as mn,
TABLE3.M
FROM TABLE1
INNER JOIN TABLE2
ON TABLE1.A = TABLE2.B
INNER JOIN TABLE3
ON TABLE2.C=TABLE3.D
Where TABLE1.K=123 AND TABLE2.L=456 ) t
Where m = mn
If I am following correctly, you can use qualify:
SELECT TABLE1.X, TABLE2.Y, TABLE3.Z
FROM TABLE1 INNER JOIN
TABLE2
ON TABLE1.A = TABLE2.B INNER JOIN
TABLE3
ON TABLE2.C = TABLE3.D
QUALIFY TABLE3.M = MIN(CASE WHEN TABLE1.K = 123 AND TABLE2.L = 456 THEN TABLE3.M END) OVER ();
I have a query where I'm doing a self join on TableA on 'Id1' and 'Id2'. I then do an inner join on TableB. The table with the self join as 2 keys (Id1,Id2). I'm trying to get the records that do not match up with the Id in Table3. Is it a condition that I need to add on the join? Thanks!
SELECT *
FROM TableA t1
JOIN TableA t2 ON t1.Id1 = t2.Id2
JOIN TableB t3 ON t1.Id1 = t3.Id
EDIT :
SELECT *
FROM UCDetails ucd1
JOIN MS et ON ucd1.UKey = TRY_CAST(et.SubKey AS bigint)
JOIN dbo.UCDetails ucd2 ON ucd1.UKey = ucd2.ETTSubkey
WHERE ucd1.ETTSubkey IS NULL
Sorry, I should of been more specific, so here is the query. What I want is to take only the record from ucd1 or ucd2 where if the ucd1 ETTSubkey IS NULL and the 'UKey' DOES NOT match the 'et.Subkey'. I can pull the records with this join but I only want to take the 'UCD' record where there isn't a match with the 'Subkey' on the et table.
If you want rows where either id does not match in tableB, then use not exists:
select a.*
from tableA a
where not exists (select 1
from tableB b
where b.id = a.id1
) or
not exists (select 1
from tableB b
where b.id = a.id2
) ;
I'm trying to get the records that do not match up with the Id in
Table3
If by match up you mean that TableB's Id is equal to either Id1 or Id2 in TableA, then you only need a LEFT join that filters out the matching rows:
SELECT a.*
FROM TableA a LEFT JOIN TableB b
ON b.Id IN (a.Id1, a.Id2)
WHERE b.Id IS NULL
I have two table a and b
table a
ID
a
b
c
table b
ID Value
a 1
b 2
default 0
So I want to join two tables on ID when exactly matching, otherwise use default value
The desired results
ID Value
a 1
b 2
c 0
Use a LEFT OUTER JOIN for that purpose like
select t1.ID, COALESCE(t2.Value, 0) as Value
from tablea t1
left join tableb t2 on t1.ID = t2.ID;
Try this:
SELECT a.ID, b.Value
FROM a
INNER JOIN b
ON a.ID = b.ID
UNION ALL
SELECT a.ID, b.Value
FROM a
CROSS JOIN b
WHERE
a.id <> b.id
This will provide you with all matching IDs, then the UNION of the CROSS JOIN query should provide the default value for non-matching IDs.
Try this:
SELECT t1.ID,
COALESCE(t2.Value, (SELECT Value FROM tableb t3 WHERE ID ='default')) AS Value
FROM tablea t1
LEFT JOIN tableb t2 on t1.ID = t2.ID;
I have a table t1. It has columns [id] and [id2].
Select count(*) from t1 where id=1;
returns 31,189 records
Select count(*) from t1 where id=2;
returns 31,173 records
I want to know the records where id2 is in id=1 but not in id=2.
So, I use the following:
Select * from t1 a left join t1 b on a.id2=b.id2
Where a.id=2 And b.id=1
And b.id2 Is Null;
It returns zero records.
Using an inner join to see how many records have id2 in common, I do...
Select * from t1 a inner join t1 b on a.id2=b.id2
Where a.id=2 And b.id=1;
And that returns 31,060. So where are the extra records in my first query that don't match?
I am sure I must be missing something obvious.
Sample Data
id id2
1 101
1 102
1 103
2 101
2 102
My expected results is to find the record with '103' in it. 'id2' not shared.
Thanks for any help.
Jeff
You are attempting to do what is generally called an exclude join. This involves doing a LEFT JOIN between two tables, then using a WHERE clause to only select rows where the right table is null, i.e. there was no record to join. In this way, you select everything from the left table except what exists in the right table.
With this data, it would look something like this:
SELECT
t1.id,
t1.id2
FROM test_table t1
LEFT JOIN
(SELECT
id,
id2
FROM test_table
WHERE id = 2) t2
ON t2.id2 = t1.id2
WHERE t1.id = 1
AND t2.id IS NULL --This is what makes the exclude join happen
And here is a SQLFiddle demonstrating this in MySQL 5.7 with the sample data you provided.
I think maybe Access changes the left join to an inner join when you add a where clause to filter rows (I know SQL Server does this), but if you do the filtering in derived tables it should work:
select
a.*
from
(select * from t1 where id = 1) a
left join
(select * from t1 where id = 2) b
on a.id2 = b.id2
where b.id2 is null