a complex sql query with outer join - php

there are two tables
a
------------------------------
id | Name
------------------------------
1 | Alpha
-----------------------------
2 | Beta
-----------------------------
3 | Gamma
-----------------------------
4 | Delta
-----------------------------
and another table b with foreign key of table a
b
-----------------------------
id | a_id | Film
-----------------------------
1 | 1 | Bladerunner
-----------------------------
2 | 1 | Star Wars
-----------------------------
3 | 3 | Superman
-----------------------------
4 | 4 | Rollerball
-----------------------------
Write an SQL query using outer join to get all names from table ā€œaā€ that don't have a film starting with ā€œSā€.
Query result should be:
Beta
--------
Delta

Use correlated subquery with not exists
DEMO
SELECT *
FROM tablea a
LEFT JOIN tableb b
ON a.id = b.a_id
WHERE NOT EXISTS (SELECT 1
FROM tableb b1
WHERE b.a_id = b1.a_id
AND film LIKE 'S%')
OR you can use below query to avoid subquery
SELECT NAME,
Sum(CASE
WHEN film LIKE 'S%' THEN 1
ELSE 0
END)
FROM t1 a
LEFT JOIN t2 b
ON a.id = b.a_id
GROUP BY NAME
HAVING Sum(CASE
WHEN film LIKE 'S%' THEN 1
ELSE 0
END) = 0
OUTPUT:
name
Delta
Beta

SELECT a.NAME
FROM a
LEFT JOIN b
ON a.id = b.a_id
WHERE a.NAME NOT IN (SELECT a.NAME
FROM a
LEFT JOIN b
ON a.id = b.a_id
WHERE b.film LIKE 's%')
GROUP BY a.NAME
output
Beta
Delta
according to the OPs question which he has not mentioned and just gave output part in his question... he wants all the name of the table a where film name do not start with letter S from table b. the above query fullfilled the requirements of OPs completely and in most standard way.
OP just mentioned the join in the question but he do not mentioned that he want those id name also which do not exist in table b in a_id i.e the output part beta.

use substring and join
select a.name from t1 a left join
t2 b on a.id=b.a_id
where a.id not in ( select b.a_id from t2 b
where
upper(substring(b.Film,1,1)) like '%S%' and b.a_id is not null
)
output
name
Delta
Beta
demo link

Related

MySQL Join two tables on multiple records

I have two tables:
Table1:
- id
- name
- table2_id1
- table2_id2
- table2_id3
Table2:
- id
- name
Table1:
id | name | table2_id1 | table2_id2 | table2_id3
1 | blabla | 1 | 2 | 3
2 | blabla2 | 2 | 3 | 1
Table2:
id | name
1 | aaa
2 | bbb
3 | ccc
I would like to display a name from Table1 and many names from Table2 which are joined, example:
*blabla | aaa | bbb | ccc*
I hope you get what I mean.
EDIT:
I tried something like this:
SELECT Table1.name, Table2.name, Table2.name, Table2.name<BR>
FROM Table1 JOIN Table2 ON<BR>
You can use left join queries:
SELECT a.name as "name", b.name as "table2_id1_name", c.name as "table2_id2_name", d.name as "table2_id3_name"
FROM Table1 a
LEFT JOIN Table2 b ON (a.table2_id1 = b.id)
LEFT JOIN Table2 C ON (a.table2_id2 = c.id)
LEFT JOIN Table2 d ON (a.table2_id3= d.id)
Hope it work as you expect. :)
SELECT a.name, b.name, c.name, d.name
FROM Table1 a, Table2 b, Table2 c, Table2 d
WHERE a.table2_id1 = b.id
AND a.table2_id2 = c.id
AND a.table2_id3= d.id

many to many query mysql return duplicate rows

i have 2 tables
1 resources
id | name | type
1 | X | form
2 | YY | post
3 | ZZ | container
2 res_res
id | parent_id | son_id
1 | 1 | 2
2 | 3 | 1
now i want to select resource.*, res_res.id of all resources related to resource id (1)
expected result
link_id | id | name | type |
1 | 2 | YY | post |
2 | 3 | ZZ | container
my query
1:
SELECT distinct r.* FROM `resources` as r
join res_res as l on (l.parent_id=r.id or l.son_id=r.id)
where l.parent_id = 2 or l.son_id = 2
this query run as expected and return result i want except that it doesnt include the id or the link (id from resource_resource table) , yet if i run this
2:
SELECT distinct l.id as link_id,r.* FROM `resources` as r
join res_res as l on (l.parent_id=r.id or l.son_id=r.id)
where l.parent_id = 2 or l.son_id = 2
this return so many duplicate rows; so what am i doing wrong ?
I thin the problem is that my join condition return both parent-id and son-id when row match, so duplicate happens, I need to put an if case in select so that I only select other field .
is there a better way to select all resources related to resource.id X and include the join id ?
i dont like using group_by cause it writes a temp. table which slow down my performance alot.
thanks
Possibly use a UNION instead:-
SELECT l.id AS link_id, l.son_id AS id, r.name, r.type
FROM `resources` AS r
INNER JOIN res_res AS l ON l.parent_id = r.id
WHERE l.son_id = 1
UNION
SELECT l.id AS link_id, l.parent_id AS id, r.name, r.type
FROM `resources` AS r
INNER JOIN res_res AS l ON l.son_id = r.id
WHERE l.parent_id = 1
Your join condition is wrong as it matches against the son element even when parent is the one you need.
SELECT l.id as link_id,r.*
FROM `resources` as r
CROSS JOIN res_res as l
WHERE (l.parent_id = 2 AND l.parent_id=r.id) OR (l.son_id = 2 AND l.son_id=r.id)

Replace value with related value

I have a table which shows the details of galleries, each entry has a Gallery_ID, one of the fields is gallery_parent which is 0 if the record has no parent and then number of its parent if it does.
ID| Name | parent
1 | gallery A | 0
2 | gallery B | 0
3 | gallery C | 0
4 | gallery D | 1
5 | gallery E | 2
How can I replace the parent gallery number with the parent gallery name?
you need two join the table to itself using LEFT JOIN
SELECT a.ID,
a.Name,
b.Name as ParentName //-- you can apply COALESCE here
FROM tableName a
LEFT JOIN tableName b
ON a.parent = b.id
SQLFiddle Demo
SQLFiddle Demo (with COALESCE)
Above answer shows how to select the data and if you do want to update and if the parent is a varchar, you can do the following
UPDATE gal t1
LEFT JOIN gal t2 ON t1.parent=t2.ID
SET t1.parent = t2.name

Querying according to the newest related object

I have two entities with an 1-N relation, like this :
table_a
-------
id
name
table_b
------
id
table_a_id
name
status
created_at
I'm looking for a way in MySQL and especially with Doctrine ORM to query table_a with a "where" clause on table_b that affect only the last associated table_b record.
Supposing I have the following records :
table_a
----------------------------
id | name
----------------------------
1 | john
2 | mary
3 | chuck
table_b
--------------------------------------------------
id | table_a_id | name | status | created_at
--------------------------------------------------
1 | 1 | blue | 1 | 2000-01-01
2 | 1 | red | 1 | 2012-12-31
3 | 2 | yellow | 1 | 2000-01-01
4 | 2 | green | 0 | 2012-12-31
So I want to tell MySQL/Doctrine :
GIVE ME the table_a records
WHICH HAVE table_b records
AND status = 1 ON the last related elements (according to the created_at field)
This should only return :
table_a
----------------------------
id | name
----------------------------
1 | john
According to the book SQL Antipatterns, this type of join with the proper indexes can often perform better than a subquery. So, try this method out too:
SELECT a.*
FROM table_a a
JOIN table_b b1
ON b1.table_a_id = a.id
AND b1.status = 1
LEFT JOIN table_b b2
ON b2.table_a_id = a.id
AND b2.created_at > b1.created_at
WHERE b2.table_a_id IS NULL
If there could be two rows from table_b with status 1 that have the same table_a_id and created_at date, then you will need DISTINCT to avoid duplicates:
SELECT DISTINCT a.*
FROM table_a a
JOIN table_b b1
ON b1.table_a_id = a.id
AND b1.status = 1
LEFT JOIN table_b b2
ON b2.table_a_id = a.id
AND b2.created_at > b1.created_at
WHERE b2.table_a_id IS NULL
Not sure about the "Doctrine", but a MySQL query could be
select
a.ID,
a.Name
from
table_b B
join table_a A
on B.table_a_id = A.ID
where
B.status = 1
order by
B.Created_At DESC
limit 1

Mysql subquery how can i get only all records from Table1 and if no match found with Table2 still list them as null or something else?

1) I have two table:
+------ +---------
topic mytask
+--------- +---------
ID | What ID | TopicID
---------- ------------
1 | A 1 | 1
2 | B
2) I have SQL as below:
SELECT
a.id, b.id
FROM
topic a
JOIN (
SELECT
b.id,b.topicid
FROM
mytask b
) b on (b.topicid=a.id)
3) I have output as below (1 ROW ONLY):
ID | ID
-------
1 | 1
My expected output is as below (2 ROW, PRIORITY TO TOPIC BY LISTING THEM ALL) :
a.ID | b.ID
-------------
1 | MATCHED - OK - TAKE IT!!!
2 | NULL or what,ever...
How can i do that?
Use a left outer join:
SELECT
a.id, b.id
FROM
topic a
LEFT JOIN (
SELECT
b.id,b.topicid
FROM
mytask b
) b on (b.topicid=a.id)
and simplify the query to
SELECT
a.id, b.id
FROM
topic a
LEFT JOIN
mytask b ON b.topicid = a.id

Categories