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
Related
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.
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
I have three different SQL tables I need to join:
table "internet" with columns id|type|status
table "type_list" with columns id|type_name
table "status_list" with columns id|status_name
I want to output text from the two other tables (type_list, status_list) but not values as numbers which currently I have in table "internet".
I also don't want to make lazy programming - PHP array to make ID's equal to something like
$type_list = array("1"=>"VDSL2","2"=>"ADSL");
$status_list = array("1"=>"Pending","2"=>"Active");
because the text is already in the tables, i just dont know how to join them and output the text as query combined together in one query.
Use JOIN
SELECT i.id, type_name, status_name
FROM internet i
LEFT OUTER JOIN type_list t ON t.id = i.type
LEFT OUTER JOIN status_list s ON s.id= i.status
Read the MySQL doc for more informations.
Just write the select with the fields you want.
select internet.id,type_name,status_name from internet
inner join type_list
on type_list.id=internet.id
inner join status_list
on status_list.id=internet.id
For this you need a LEFT JOIN, like so:
SELECT i.id, t.type_name, s.status_name
FROM internet AS i
LEFT JOIN type_list AS t ON t.id = i.id
LEFT JOIN status_list AS s ON s.id= i.id
From your question, it is unclear what field you would like to join the queries on. In the above example, the queries are joined on the id field.
Please also note that the AS is not actually necessary, I have just put it in there to make it clear what is going on
So I have a query that should get all posts from a table while linking the posts categories and the user that created the post. What I am getting though is just a single post returned, not all posts. Below is the schema:
Posts
=====
id
Categories
==========
id
Post categories
===============
postID
categoryID
And here is the SQL code I have so far, kinda deep but it gets all categories concatenated into a single field.
SELECT
blgpostcategories.*,
blgcategories.id,
GROUP_CONCAT(blgcategories.name) AS categories,
blgposts.*,
users.firstName,
users.id AS usersId,
users.lastName,
users.email
FROM blgposts
RIGHT OUTER JOIN blgpostcategories
ON blgposts.id = blgpostcategories.postID
RIGHT OUTER JOIN blgcategories
ON blgpostcategories.categoryID = blgcategories.id
INNER JOIN users
ON blgposts.userID = users.id
UPDATED Query from JNK - Still only returning a single row :-(
SELECT
blgpostcategories.*,
blgcategories.id,
GROUP_CONCAT(blgcategories.name) AS categories,
blgposts.*
FROM blgposts
LEFT OUTER JOIN blgpostcategories
ON blgposts.id = blgpostcategories.postID
LEFT OUTER JOIN blgcategories
ON blgpostcategories.categoryID = blgcategories.id
In an answer by Adam Robinson to a similar question
Because you're using an aggregate in
your query (GROUP_CONCAT), your query
is being grouped. Since you have no
group by clause, your group is the
entire result set (hence seeing every
tag the author has used). Because
MySQL allows for using non-grouped
columns in grouped statements, you
aren't getting an error, but you
aren't getting the query that you
want.
In order to retrieve the proper
results, you need to group your query
on thread.id.
In your case just adding GROUP BY blgcategories.id should do it
Two things I see right off the bat:
1 - Do a LEFT OUTER JOIN not a RIGHT. RIGHT means "show me all the stuff in the right table, whether or not I have anything matching in the left table." You want everything from blogposts so do a left.
2 - Your INNER JOIN may be an issue as well. Are you sure users is populated fully?
EDIT:
The issue is you are using an aggregate function without a GROUP BY! Take out the GROUP_CONCAT() and it should work fine.
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.