I'm working with a legacy database that uses a three column key for products. I want to select all products that have a status of 'A' or that have a matching record in a second table. If it were a single column primary key (like 'id'), I would do it this way:
SELECT * FROM `product`
WHERE `status` = 'A'
OR `id` IN (SELECT `foreign_key` FROM `table2`)
I can't figure out how to do the IN-clause subselect with three keys though. I suppose I can concatenate the keys together and compare the strings, but that seems horribly inefficient. Is there a way to do this without concatenation?
You can LEFT JOIN table product and table2 on the composite key, then status = 'A' OR table2.id IS NOT NULL
A LEFT [OUTER] JOIN can be faster than an equivalent subquery because the server might be able to optimize it better
SELECT * FROM product p1
WHERE status = 'A'
OR EXISTS (SELECT *
FROM table2 t2
WHERE t2.id = p1.foreign_key
AND t2.other_key = p1.secret_key
...
);
Do a left join :)
SELECT p.* FROM product p
LEFT JOIN table2 t2 on p.key1 = t2.key1 and p.key2 = t2.key2 and p.key3 = t2.key3
WHERE status = 'A' OR t2.key1 IS NOT NULL
You could use a UNION:
SELECT *
FROM 'product'
WHERE 'status' = 'A'
UNION
SELECT *
FROM 'product'
JOIN 'table2'
ON (product.id = table2.foreign_key
AND ...)
Related
Here is what I currently have which returns 3 columns for patient_id, group_concat_1, and group_concat_2:
SELECT patient_id,
(SELECT GROUP_CONCAT(column1) FROM
table1 where patient_id = patient.id
) group_concat_1,
(SELECT GROUP_CONCAT(column1) FROM
table2 where patient_id = patient.id
) group_concat_2
FROM patient
However, I need to return a single column with group_concat_1 and group_concat_2 combined, so I tried this:
SELECT patient_id,
SELECT CONCAT(group_concat_1, group_concat_2) FROM (
(SELECT GROUP_CONCAT(column1) FROM
table1 where patient_id = patient.id
) group_concat_1,
(SELECT GROUP_CONCAT(column1) FROM
table2 where patient_id = patient.id
) group_concat_2
)
FROM patient
But his clearly doesn't work since now it can't find patient.id in the inner subquery. Any advice? Thanks!
You can concatenate directly the 2 columns:
SELECT p.patient_id,
CONCAT(
(SELECT GROUP_CONCAT(column1) FROM table1 where patient_id = p.patient.id),
(SELECT GROUP_CONCAT(column1) FROM table2 where patient_id = p.patient.id)
)
FROM patient p
I'm pretty sure you want concat_ws() for this purpose:
SELECT patient_id,
CONCAT_WS(','
(SELECT GROUP_CONCAT(t1.column1) FROM table1 t1 where t1.patient_id = p.id
),
(SELECT GROUP_CONCAT(t2.column1) FROM table2 t2 where t2.patient_id = p.id
)
) as combined
FROM patient p;
There are two reasons:
You can distinguish between the last element from table1 and the first from `table2.
If one of the tables has no matching values, this returns the results from the other.
Also note that I added table aliases and qualified column names. This is quite important when working with queries that have multiple table references -- it helps prevent some very hard to debug errors.
I should add that your original query would run in most databases. MySQL and Oracle happen to be two that don't understand nested correlation clauses.
Hello here is my table structure
I am trying to determine does record with ID 1 has child records (parent_id column ), and this should work for all record not just for specific one
Trying something like this
SELECT id, ??? as 'has_child_rows' FROM image_tree WHERE parent_id IS NULL
Any idea left join, recursion, subquery?
You can use exists and an inline correlated subquery:
select
id,
exists(select 1 from image_tree t1 where t1.parent_id = t.id) has_child_rows
from image_tree t
This returns all the rows in the table, with a boolean value that indicates whether a child record exists.
To filter on the record that has id = 1, just add a where clause:
select
id,
exists(select 1 from image_tree t1 where t1.parent_id = t.id) has_child_rows
from image_tree t
where id = 1
Another solution is using 'left join' as you mentioned:
SELECT
i.*, IF(p.parent_id IS NULL, 0, 1) AS has_child_rows
FROM image_tree i
LEFT OUTER JOIN (SELECT parent_id FROM image_tree WHERE parent_id IS NOT NULL GROUP BY parent_id) p ON i.id = p.parent_id
WHERE i.parent_id IS NULL
In practice, you need to test the performance as I have little knowledge of the table indices, quantities of records and the relations.
I am joining two tables by the regNo column. I want to add the points of Table1.points and Table2.points where the regNo matches and just incase it doesn't match I also want it be included with its points in the list as shown in the image bellow
I have read through the existing problems but not finding the solution to this e.g How can I sum columns across multiple tables in MySQL?
(
SELECT `Ex`.regNo,(`In`.`points`+`Ex`.`points`) AS 'Points'
FROM Table1`In`
LEFT JOIN Table2`Ex` ON `In`.`regNo` = `In`.`regNo`
)
UNION
(
SELECT`Ex`.regNo,(`In`.`points`+`Ex`.`points`) AS 'Points'
FROM Table1`In`
RIGHT JOIN Table2`Ex` ON `In`.`regNo` = `In`.`regNo`
);
I want it to give the list arranged as per unique (DISTINCT) regNo
You need UNION followed by GRoUP BY:
SELECT regNo, SUM(points) AS total
FROM (
SELECT regNo, points
FROM Table1
UNION ALL
SELECT regNo, points
FROM Table2
) AS u
GROUP BY regNo
You are looking for a FULL JOIN between both tables.
SELECT
COALESCE(t1.id, t2.id) id
COALESCE(t1.regNo, t2.regNo) regNo
COALESCE(t1.points, 0) + COALESCE(t2.points 0) points
FROM
table1 t1
FULL JOIN table2 t2 on t1.regNo = t2.regNo
NB : you did not specify what you expect to be done to generate the new id so by default the above query will display the table1.id if available, else table2.id.
If you would better generate a new, auto-incremented field, then :
SET #i=0;
SELECT
#i:=#i+1 id
COALESCE(t1.regNo, t2.regNo) regNo
COALESCE(t1.points, 0) + COALESCE(t2.points 0) points
FROM
table1 t1
FULL JOIN table2 t2 on t1.regNo = t2.regNo
Please check this. You need to use full outer join and null replacement before aggregation
select
COALESCE(table1.regno, table2.regno) regno,
sum(COALESCE(table1.points,0)) + sum(COALESCE(table2.points,0)) points
from Table1
full outer join Table2
on table1.regno = table2.regno
group by
COALESCE(table1.regno, table2.regno)
Is it possible to get 1 result where I require data from 3 tables.
First table: I will need to grab all the fields (1 row found by a primary key)
Second table: I will need to grab the field 'username' (connected to first table by 'master_id')
Third table: I will need to grab the latest added row with the associated master_id key (table has 'date', 'master_id', 'previous_name').
select top 1 first.*, second.username, third.*
from first
inner join second on first.id = second.master_id
inner join third on first.id = third.master_id
order by
third.date desc
As always there are dozens of ways to skin a cat, I'm not sure if this is optimized as the subquery methods, but it should work.
You can join the three tables together. Then, you can use a "filter" join to keep only the latest Table3 row:
select *
from Table1 t1
join Table2 t2
on t2.master_id = t1.master_id
join Table3 t3
on t3.master_id = t1.master_id
join (
select master_id
, max(date) as max_date
from Table3
group by
master_id
) as filter
on t3.master_id = filter.master_id
and t3.date = filter.max_date
You'll need a correlated subquery for that third table.
SELECT t1.*, username, date, previous_name
FROM FirstTable t1
INNER JOIN SecondTable t2 ON t1.master_id=t2.master_id
INNER JOIN
(SELECT master_id, date, previous_name
FROM ThirdTable AS t3_1
WHERE date = (
SELECT MAX(date)
FROM ThirdTable AS t3_2
WHERE t3_2.master_id=t3_1.master_id)) q1 ON q1.master_id=t1.master_id;
NOTE: Untested.
I have the following SQL:
SELECT * FROM `table` WHERE `code` = 15510642
I want to modify so that it checks another table as well, so for example:
SELECT * FROM `table`,`table2` WHERE `code` = 15510642
However that doesn't work. Please help!
Perhaps the poster means UNION because he wants results from both tables?
SELECT * FROM `table` WHERE `code` = 15510642
UNION [ALL]
SELECT * FROM `table2` WHERE `code` = 15510642
Works only when both tables contains same column (or specify them instead *)
you'll have to join the tables if there's a relation between them.
select * from table as t1, table2 as t2 where t1.code = 15510642 or t2.code=15510642
and t1.id = t2.foreignkeyid
If there's no relation you could try a union, but the fields must match. So only use fields from both tables that match.
select id, somefield, somefield2 from table1 where code = 15510642
union
select id, somefield, somefield2 from table2 where code = 15510642
Work with an inner join.
It will be something like
SELECT *
FROM Table t INNER JOIN table2 t2
ON t.Code = t2.Code
WHERE t.Code = 15510642
I hope this helps!
Tjeu