MySQL Inner Join involving three tables - php

I am working with four tables:
query,
store,
cluster_group,
tv_region
I want to retrieve query records belonging to a particular TV Region record.
A query record either belongs to a record in the store or cluster_group tables. The query table has 'store_id' and 'cluster_group_id' columns. Either will be null whilst the other will refer to a record in the store or cluster_group table. The store and cluster_group tables both have a 'tv_region_id' column.
To retrieve query records that belong to a TV Region record that has an id = 2, I wrote the following SQL statement:
SELECT query.id AS query_id, cluster_group.name as cluster_name, cluster_group.tv_region_id as cluster_tv_region, store.store_name
FROM query
INNER JOIN cluster_group
ON cluster_group.id=query.cluster_group_id
INNER JOIN store
ON store.id=query.store_id
WHERE cluster_group.tv_region_id = 2
AND store.tv_region_id = 2;
The problem is that it returns zero records even though there are query records that belong to the specified TV Region (via a cluster group or store record). I may have misunderstood how 'inner join' works.
I'm working with Doctrine 2 and have attempted the query using the left join but it still returns nothing, I guess this is because its returning null values too. How do I get it to return only the query records I am interested in and no null values?
Appreciate if someone can point me in the right direction to retrieve the relevant query records.

You will need to use OUTER joins, or possibly LEFT
INNER joins will only return data where there is a matching record on both sides. As you state in your question you only get a match on one side or the other, therefore there is never going to be a matching record across both store and cluster
Jeff Atwood has a good explanation of the join types on his blog http://www.codinghorror.com/blog/2007/10/a-visual-explanation-of-sql-joins.html

Try this:-
SELECT query.id AS query_id, cluster_group.name as cluster_name, cluster_group.tv_region_id as cluster_tv_region, store.store_name
FROM query
LEFT OUTER JOIN cluster_group
ON cluster_group.id=query.cluster_group_id
AND cluster_group.tv_region_id = 2
LEFT OUTER JOIN store
ON store.id=query.store_id
AND store.tv_region_id = 2
EDIT - no experience of doctrine, but you could try using a UNION:-
SELECT query.id AS query_id, cluster_group.name as cluster_name, cluster_group.tv_region_id as cluster_tv_region, NULL AS store_name
FROM query
INNER JOIN cluster_group
ON cluster_group.id=query.cluster_group_id
AND cluster_group.tv_region_id = 2
UNION
SELECT query.id AS query_id, NULL as cluster_name, NULL as cluster_tv_region, store.store_name
FROM query
INNER JOIN store
ON store.id=query.store_id
AND store.tv_region_id = 2

It works like this for me:
from table1 inner join table2 on table1.id = table2.id
inner join table3 on table1.id = table3.id

Related

Combining two MySQL tables yet want one column to equal another

I am trying to join two tables together in a view. My first table combines two tables but now I am trying to join that table to a second table. I am trying to use a join to make sure the second table which contains roles which are performed by the user, matches up with the first table but if there are no records in the second table, I still want all the records from table 1. I know my explanation is a little confused, so my code is as follows:
CREATE VIEW `data` AS SELECT
`information`.`username`, `information`.`department`,
`information`.`company`, `information`.`title`,
`information`.`internal_number` AS `user_internal_phone`,
`information`.`external_number`AS `user_external_phone`,
`information`.`mail`, `information`.`cn` AS `name`, `information`.`hours`,
`information`.`languages`, `information`.`functions`,
`information`.`service` AS `contact_point_name_one`,
`information`.`subservice` AS `contact_point_name_two`,
`information`.`internal_phone` AS `contact_internal_phone`,
`information`.`external_phone` AS `contact_external_phone`,
`information`.`keywords`, `information`.`description`,
`information`.`provided_by`, `information`.`id`,
GROUP_CONCAT(`staff_roles`.`role` SEPARATOR ', ') AS `roles`,
`staff_roles`.`user`
FROM `information`
CROSS JOIN `staff_roles` ON `information`.`username` = `staff_roles`.`user`;
I get an error when I do an outer join and a cross join and an inner join both return rows where there is a row in both tables yet I want it to display the rows where there is nothing in the second table as well. The purpose of using a join is so that, where there is a match, the row from table 2 should match the row on table 1
Use LEFT JOIN. The LEFT JOIN keyword returns all rows from the left table (table1), with the matching rows in the right table (table2). The result is NULL in the right side when there is no match.
Just replace your CROSS JOIN with LEFT JOIN
Simply use LEFT JOIN instead of CROSS JOIN:
CREATE VIEW `data` AS SELECT
...
FROM `information`
LEFT JOIN `staff_roles` ON `information`.`username` = `staff_roles`.`user`;
Take a look at http://www.w3schools.com/sql/sql_join_left.asp for further details about why LEFT JOIN.

PHP MySQL query WHERE equals AND row does not exist

I have been looking and cant find an answer to what im trying to do.
I dont know if a query can be created in the following way.
$sql_call = "SELECT table.item,table.item,table.item FROM cust
LEFT JOIN contact ON cust.id = contact.client_id
LEFT JOIN survey_audit ON cust.id = survey_audit.cust_id
WHERE cust.clinic='$clinic_id' AND contact.participate='1' AND survey_audit.survey_id != '$post_survey_id'";
The query above, does not do what Im trying to do, and that is:
Get data from tables WHERE cust.clinic=something AND contact.participate=something AND (this is the part im not sure about) inside Survey_audit table, there is no row with this id.
Is it possible to ask sql to find a result where something=something AND is no row in specific table?
You are sort of on the right track. You simply need to look for cases where survey_audit.survey_id is NULL.
SELECT table.item,table.item,table.item
FROM cust
LEFT JOIN contact
ON cust.id = contact.client_id
LEFT JOIN survey_audit
ON cust.id = survey_audit.cust_id
WHERE cust.clinic='$clinic_id'
AND contact.participate='1'
AND survey_audit.survey_id IS NULL
Here is a very useful resource for helping you determine how to form more complex join scenarios. Your case is the 4th example on this page.
http://blog.codinghorror.com/a-visual-explanation-of-sql-joins/
You can exclude all the elements of the table using a subquery:
$sql_call = "SELECT table.item,table.item,table.item FROM cust
LEFT JOIN contact ON cust.id = contact.client_id
LEFT JOIN survey_audit ON cust.id = survey_audit.cust_id
WHERE cust.clinic='$clinic_id' AND contact.participate='1' AND survey_audit.survey_id NOT IN (SELECT survey_id FROM Survey_audit);
Yes it is possible, you should read more about other types of joins in mysql there are 4 types of joins
INNER JOIN (JOIN) - matching id's in both tables
LEFT JOIN - matching id in table A and can be null in Table B
RIGHT JOIN - matching id in table B and can be null Table A
OUTER JOIN - can be null in both tables
Recommend you to read the following article
http://www.sitepoint.com/understanding-sql-joins-mysql-database/
So for your question I guess you should use RIGHT JOIN survey_audit instead of LEFT JOIN survey_audit

MSSQL Joining 3 Tables with more than 1 row to a single line result over multiple records

Ok, I'll try to explain this as best I can here.
I have multiple tables that are to be connected through a JOIN where certain reference points meet.
In one of the tables, there are 2 or more results over several rows that I need to bring back to separate columns.
In the diagram below (I hope that explains it better), T2.ColA is connected to T3.ColA and T1,ColA is connected to T2.ColB.
In ColC of T1, there is a latest record. These are the only ones that are required to results. Note that ColC could be different dates between rows 1 and 2 for example. But it needs the latest for each ColB based on ColA.
But in T1, there are two rows which need Col B to return to the result in separate columns.
By the way, this is just one entry - there will be thousands of rows that need to return a result - not just 1.
Let me know if you need any more info.
Try this query
select t1.cola,t2.cola,t1.colb,t2.colb,t3.colb FROM table2 t2 INNER JOIN table1 t1 ON t1.cola = t2.colb INNER JOIN table3 ON t3.cola =t2.cola
Possibly this could solve your query..
SELECT T1.COLA, T1.COLB, T2.COLA, T2.COLA
FROM
TABLE1 T1 INNER JOIN TABLE2 T2
INNER JOIN TABLE3 T3
WHERE
T1.COLC = (
SELECT MAX(T4.COLC) FROM TABLE1 T4 WHERE T4.COLA = T1.COLA
)
** But as you have specified in your dig, it's not possible to display 1123, 3211 in a single row. It has to be in two different rows, coz its changes dynamically depending on the row count. You can modify as you want using your front end application.

mysql join select explained

I have two tables: 'posts' and 'users' every post has a 'ref_id' column to get the user id who posted it.
Now, I am getting posts this way:
$this->db->query("SELECT * FROM posts WHERE time > '$timeLimit' LIMIT 50");
I can't understand how to join every result to get the poster related data as well. What I am doing right now is basically a loop inside a loop, where foreach of the result, get their user info. But it is pretty obvious that this is very wrong,
Apparently I need to start using joins, but how does one do it? this should be a really simple example to work with, I suppose.
Any help? Thank you.
SELECT posts.*, users.*
FROM posts
INNER JOIN users
ON posts.posted_by = users.id;
Like this:
SELECT
posts.*,,
users.Username
FROM posts
INNER JOIN users ON posts.ref_id = users.user_id;
Explanation:
To JOIN to any tables with each others, there are two things; the JOIN type and the join condition. There are three main types of join:
INNER JOIN, only the rows that match the join condition will be returned from the two tables no more rows. But:
LEFT OUTER JOIN, when you join two tables you will have one on the left of the join keyword and the other one will be in the right:
FROM Table1 <------------- This is the left table.
LEFT OUTER JOIN table2 .... <------------- This is the right table.
In LEFT OUTER JOIN the unmatched rows from the left table will be included in the result set.
RIGHT OUTER JOIN the unmatched rows from the right table will be included in the result set.
CROSS JOIN this will perform a Cartesian product from the two tables.
In our query, the query will reutrn all the users from the users table only if the ref_id equal to the user_id column form the posts table.
For more information and explanations:
A Visual Explanation of SQL Joins.
Another Visual Representation of SQL Joins.
Join syntax in MySQL
SELECT user.name
FROM users
INNER JOIN posts
ON posts.ref_id == user.id
AND posts.time > 50
http://www.w3schools.com/sql/sql_join_inner.asp

How to get a LEFT JOINED query result without all of the NULLs

I am LEFT JOINing multiple tables as such:
SELECT * FROM table1
LEFT JOIN table2 ON table1.id = table2.fid
LEFT JOIN table3 ON table1.id = table3.fid
LEFT JOIN table4 ON table1.id = table4.fid
LEFT JOIN table5 ON table1.id = table5.fid
LEFT JOIN table6 ON table1.id = table6.fid
WHERE table2.id = '5184'
Reason being is simply because I tried regular JOIN and no results are returned unless at least one record exists in tables1-6 which is often not the case. As it stands this returns the info I want, but the problem is that a lot of the field names repeat and when I do a 'mysql_fetch_array()' in PHP it hides any field with a duplicate name.
What type of query can I do to avoid this? At the very least, how do I construct the query such that it doesn't include all the double fields which are NULL?
Thanks
I can't help but notice that you aren't selecting anything from your left joined tables. It's my understanding that joins are typically used to pull data from secondary tables where something in those tables matches a field in the primary table. I pulled this example from W3 schools:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
LEFT JOIN Orders
ON Persons.P_Id=Orders.P_Id
ORDER BY Persons.LastName
And unless this is a typo, you are selecting everything from table 1 where an id column = 5186 in table 2.
You state that your query returns the info you want, but with many nulls and overwritten values. To fix this, I would restructure your query to follow the typical format shown above, and make sure you have a proper use of the left join statement.
EDIT AFTER OP COMMENTS:
You are naming a row id from table2, so I assume you should start by pulling fid from table 2 where table2.id = 5186, then left join from the other tables where table1.id = table2.fid.
SELECT table2.fid, table1.id, table3.id, [add other tables here, and revise field names to select the ones you want]
FROM table2
LEFT JOIN table1 ON table1.id = table2.fid
LEFT JOIN table 3 ON table3.fid = table1.id
[add left joins to other tables here]
WHERE table2.id = '5186'
If this doesn't help, I suggest being more specific towards what information the tables hold, and what you are searching for. A little more detail may help us help you.

Categories