So I have two tables like this:
create table A
{
id int;
...
}
create table B
{
id int;
a_id int;
t timestamp;
...
}
A is one-to-many with B
I want to:
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id ???
But I want to return exactly one row for each entry in A which has the B with the newest t field (or null for Bs fields if it has no B entry).
That is rather than returning all A-B pairs, I want to only select the newest one with respect to A (or A-null if no B entry).
Is there some way to express this in SQL? (I'm using MySQL 5.5)
LEFT JOIN is only concerned with ensuring every row in A is returned, even if there is no corresponding joined row in B.
The need for just one row needs another condition. MySQL is limitted in its options, but one could be:
SELECT
*
FROM
A
LEFT JOIN
B
ON B.id = A.id
AND B.t = (SELECT MAX(lookup.t) FROM B AS lookup WHERE lookup.id = A.id)
Another could be...
SELECT
*
FROM
A
LEFT JOIN
(
SELECT id, MAX(t) AS t FROM B GROUP BY id
)
AS lookup
ON lookup.id = A.id
LEFT JOIN
B
ON B.id = lookup.id
AND B.t = lookup.t
You could do the following:
SELECT A.*, B.*
FROM
A
LEFT JOIN
(SELECT B.a_id, MAX(t) as t FROM B GROUP BY B.a_id) BMax
ON A.id = BMax.a_id
JOIN B
ON B.a_id = BMax.a_id AND B.t = BMax.t
you first need to get the newest t from tableB in a subquery, then join it with tableA and tableB.
SELECT a.*, c.*
FROM tableA a
LEFT JOIN
(
SELECT a_ID, max(t) maxT
FROM tableB
GROUP BY a_ID
) b on a.a_id = b.a_ID
LEFT JOIN tableB c
ON b.a_ID = c.a_ID AND
b.maxT = c.t
try this:
SELECT *
FROM tableA A LEFT JOIN
(select a_id ,max(t) as max_t
from tableB
group by a_id )b
on A.id = b.a_id
and A.t=b.max_t
Related
I think it's impossible, but I'm asking if there's a good way.
There are A table / B table / C table.
The table was joined LEFT JOIN based on table A with FK called id of each table.
At this time, I would like to output the count(*) as B table rows and C table rows based on b.id(B_CNT) c.id(C_CNT)
SELECT
*
FROM
A
LEFT JOIN B ON A.ID = B.ID
LEFT JOIN C ON A.ID = C.ID (base query)
how could I count group by b.id and c.id?
You could try:
SELECT
COUNT(DISTINCT B.ID), COUNT(DISTINCT C.ID)
FROM A
LEFT JOIN B
ON A.ID = B.ID
LEFT JOIN C
ON A.ID = C.ID
(I couldn't quite understand from your question, but I'm making an assumption that you want the distinct count of "ID" from each table)
You can use a couple of scalar subqueries. For example:
select id,
(select count(*) from b where b.id = a.id) as b,
(select count(*) from c where c.id = a.id) as c
from a
I have this query:
select a.*, b.*, (select c.* from tableC c where c.id_tableA = a.id) from tableA a inner join tableB b on a.id = b.id_tableA where b.id_user = 50;
The subquery (which is tableC) is returning me more than 1 row as expected. How can I return only 1 row from tableC so it could match with the rest of the query?
So far I have tried this:
(select c.* from tableC c where c.id_tableA = a.id limit 1)
It didn't work as mysql said:
"Operand should contain 1 column(s)"
You are mixing two things. Scalar subquery in SELECT list should return only one value (both row and column). Using LIMIT 1 will get you one row, but still many columns.
So you could specify column name:
select a.*, b.*,
(select c.col_name from tableC c where c.id_tableA = a.id order by .. limit 1)
from tableA a
inner join tableB b on a.id = b.id_tableA
where b.id_user = 50;
or use normal JOIN:
select a.*, b.*, c.*
from tableA a
inner join tableB b
on a.id = b.id_tableA
left join tableC c
on c.id_tableA = a.id
where b.id_user = 50;
if column id from table C is a primary key then it should have no problem
but if no, try to add another condition that will filter your subquery results like ,
for example here is the start_date:
SELECT a.column_1, b.column_2,
(SELECT column_3 FROM tableC
WHERE (id = a.id
AND (start_date = (SELECT MAX(b.start_date)
from tableC as c
where a.id = c.id ))) AS column_3
FROM tableA as a INNER JOIN
tableB as b ON b.id = a.id
WHERE b.id_user = 50;
I have 2 tables in my SQL database. Let's call them Table A and Table B.
I have joined both the tables using left join on ID = AID. Table A has a field by name ID and Table B has field AID and Price.
The problem is Table B can have multiple prices for the ID present in Table A.
The requirement is - If only one price is present in Table B corresponding to ID in table A then it should return that price.
If more than one price is present in table B for an ID in table A then I should get the price as Zero/null.
Query -
SELECT DISTINCT A.ID,B.Price
from A
left join B
on A.ID = B.AID
where "some condition"
Use Count() with Over() window function to find the count of records for each ID then based on count return the price
Try this way
SELECT DISTINCT A.ID,
case when count(1) over(partition by A.ID) > 1 then NULL else B.Price end
from A
left join B
on A.ID = B.AID
For Mysql
SELECT DISTINCT a.id,
CASE
WHEN c.aid IS NULL THEN NULL
ELSE b.price
END
FROM a
LEFT JOIN b
ON a.id = b.aid
LEFT JOIN (SELECT aid
FROM b
GROUP BY aid
HAVING Count(1) = 1) c
ON a.id = c.aid
For SQL Server (should work for MySQL too). One sub-query (you can put in CTE) that shows only AIDs that have only one price:
SELECT A.ID,
B.Price
FROM A
LEFT JOIN (
SELECT AID
FROM B
GROUP BY AID
HAVING COUNT(Price) = 1
) as C
ON C.AID = A.ID
LEFT JOIN B
ON C.AID = B.AID
Use below query. It should work.
SELECT A.ID, o.Price
FROM A
OUTER APPLY
(
SELECT IIF(COUNT(B.Price)>1,NULL,MAX(B.Price)) AS Price
FROM B
WHERE B.AID = A.ID
) AS o;
I have a situation where we have inserted duplicated data into some tables.
Given the following database schema, I want to find all records with s_id and co_id combinations associated to more than 1 record from table A. The highlighted rows are the rows I'm looking for, based off of finding the duplicates I need to find the id's from table A associated to the duplicate records.
I'm able to group by s_id & co_id to determine potential duplicates, but because Table B is a 1:M, this isn't entirely accurate.
Select c.s_id, c.co_id, Count(*)
from c
INNER JOIN b on c.b_id = b.id
INNER JOIN a on a.id = b.a_id
Group By c.s_id, c.co_id
Having count(*) > 1;
I think you just want count(distinct):
Select c.s_id, c.co_id, Count(distinct a.id)
from c join
b
on c.b_id = b.id join
a
on a.id = b.a_id
Group By c.s_id, c.co_id
having count(distinct a.id) > 1;
Gordon's answer will get you the s_id and co_id values. If you need to trace those back to a then try this:
select distinct a.id
from
a inner join b on b.a_id = a.id inner join c on c.b_id = b.id inner join
(
select c.s_id, c.co_id
from a inner join b on b.a_id = a.id inner join c on c.b_id = b.id
group by c.s_id, c.co_id
having count(distinct a.id) > 1
) as dups
on dups.s_id = c.s_id and dups.co_id = s.co_id
I'd like to bring in just the most recent date row along with other fields from Table B that would include all values for multiple columns in Table A, even if there is no value in Table B.
The following query works, but only returns values that exist in both Table A AND in Table B. How do I include all of A and the most recent date row of B?
Many Thanks!
SELECT A.person_id,
A.second_field,
B.create_timestamp,
B.second_field
FROM (
SELECT B.person_id, max(B.create_timestamp) as create_timestamp
FROM Table_B B
GROUP BY B.person_id
) BMaxDate
LEFT JOIN Table_B B
ON BMaxDate.person_id = B.person_id AND
BMaxDate.create_timestamp = B.create_timestamp
LEFT JOIN Table_A A ON BMaxDate.person_id = A.person_id
You have to use Table_A as the first table in the LEFT JOIN operation chain:
SELECT A.person_id,
A.second_field,
B.create_timestamp,
B.second_field
FROM Table_A AS A
LEFT JOIN (
SELECT B.person_id, max(B.create_timestamp) as create_timestamp
FROM Table_B B
GROUP BY B.person_id
) AS BMaxDate ON BMaxDate.person_id = A.person_id
LEFT JOIN Table_B AS B
ON BMaxDate.person_id = B.person_id AND
BMaxDate.create_timestamp = B.create_timestamp
If you want all from table_A and use a left join you have to put table_A first.
And for Sql Server you can use the with clause for more readable sub query. Mysql doesn't support the with clause.
With(
SELECT B.person_id, max(B.create_timestamp) as create_timestamp
FROM Table_B B
GROUP BY B.person_id
) AS BMaxDate
SELECT A.person_id,
A.second_field,
B.create_timestamp,
B.second_field
FROM Table_A AS A
LEFT JOIN BMaxDate ON BMaxDate.person_id = A.person_id
LEFT JOIN Table_B AS B ON BMaxDate.person_id = B.person_id
AND BMaxDate.create_timestamp = B.create_timestamp