I have four tables
post
-------------
post_id
cat_id
posts
post_category
-------------
cat_id
cat_name
users
-------------
user_id
user_name
user_category_map
-------------
user_id
cat_id
I want all posts added by all users in all post categories
I have written this query
SELECT posts
FROM post p, users u, user_category_map ucm
WHERE p.cat_id = ucm.cat_id
AND ucm.user_id = u.user_id
but I am getting repeated posts. Is my table structure correct and normalized properly. I am not able to correctly grab the logic. Is the join I put is correct?
Here you received the full cartesian product of all tables, and filter it by " p.cat_id = ucm. cat_id and ucm.user_id = u.user_id" condition.
Query like this typically converted to optimized join versions - merge, nested loop, index or hash join.
During cartesian product A*B*C every row from A will be repeat B*C times.
Your query "all posts added by all users in all post categories" is
select * from post
The design does not look correct. Instead of a reference table for user_category, you should have a reference table for user_post. In current scenario, if same user adds multiple posts for same category, you will end up having duplicate rows in user_category_map
Related
I have 4 tables and I wish to use a mysql inner join to the users name (table 1) and type of fav(table 4). Inorder to do this, I need to use user_id to get get corresponding fav_id on table 2, then use the fav_id to get type_of_fav_id on table 3, and finally use type_of_fav_id on table 3 to get type_of_fav on table 4. I will appreciate any help.
Table 1
Users
----------
user_id
first_name
last_name
Table 2
user_favorite
--------
user_fav_id
user_id
fav_id
Table 3
favorites
--------
fav_id
type_of_fav_id
Table 4
types_of_fav
--------
type_of_fav_id
type_of_fav
It's pretty straightforward, actually. Just join each of the four tables, linking the primary key of each to its foreign key counterpart in the following table. Then you can reference the fields that you want in your SELECT clause.
SELECT u.first_name, u.last_name, tof.type_of_fav
FROM users u
JOIN user_favorite uf ON u.user_id = uf.user_id
JOIN favorites f ON uf.fav_id = f.fav_id
JOIN types_of_fav tof on f.type_of_fav_id = tof.type_of_fav_id
It's a good idea to set up abbreviations of the table names as I have it here. You don't have to do that, but it's more concise and easier to work with. If you don't do it, you have to reference the full table name, to avoid ambiguity in field references: JOIN user_favorite on users.user_id = user_favorite.user_id, for example. That gets pretty long-winded.
If you don't include the tables when referencing the fields, the parser doesn't know which field you're referencing, since your field names aren't unique in your entire schema. So, you'll get an ambiguous field reference error.
I have a table that contains the information of all the posts, table's name is "paylasimlar". and I have another table that contains the information of every like action, table's name is "begeniler". It has 2 columns:
1-User ID of who liked the post
2-The Post ID that liked
The thing I want to do is to write a query with joins that returns all the information of the posts from table "paylasimlar" with the count of likes it got. The problem I ran into is; if a post hasn't got liked yet there would be no information on the "begeniler" table and it would not return the information of that table as a row. Can someone help?
select a.*,count(b.PostID) from paylasimlar a
left join begeniler b on a.PostID and b.PostID group by b.PostID
I need to select all the messages (first posts and replies) posted in an array of specific categories (forums) in Drupal.
First posts are stored in field_data_body, replies are stored in field_data_comment_body.
The structure of field_data_body and field_data_comment_body is the same, in the column body_value there's the content of the posts and in the column entity_id their unique ID.
The table field_data_taxonomy_forums contains the entity_id column and the taxonomy_forums_tid column (which are the IDs of the forum categories). The table taxonomy_term_data contains the columns tid (which is the same of taxonomy_forums_tid and the description column (which is the title of the forum category).
So, I'm looking for a query that allows me to select the body of the posts (both first posts and replies) and the description of the forum specifying an array of tids (i.e. the IDs of the forum categories), that I'll manually find in the taxonomy_term_data table.
So, for example I'm looking for the query that allows me to SELECT the posts "belonging" to tids 1456,7622,862 and the relative tid description.
Here's a screenshot of the field_data_body table :
I think, it would be better for us to split the task into 2 subtasks:
Find the bodies of the posts, belonging to a particular tid.
Find all the comments of the body, belonging to a particular tid.
We'll need to use these tables:
field_data_taxonomy_forums
field_data_body
comment
field_data_comment_body
Database structure:
Finding the bodies
SELECT
taxonomy_forums.taxonomy_forums_tid AS tid,
body.entity_id,
body.body_value AS body
FROM
field_data_taxonomy_forums AS taxonomy_forums
INNER JOIN
field_data_body AS body
ON
body.entity_id=taxonomy_forums.entity_id
WHERE
taxonomy_forums.taxonomy_forums_tid IN (9);
Finding the comments for the bodies
Here we'll need comments table, that unites field_data_body and field_data_comment_body.
SELECT
taxonomy_forums.taxonomy_forums_tid AS tid,
comment_body.entity_id,
comment_body.comment_body_value AS body
FROM
field_data_taxonomy_forums AS taxonomy_forums
INNER JOIN
field_data_body AS body
ON
body.entity_id=taxonomy_forums.entity_id
INNER JOIN
comment
ON
comment.nid=body.entity_id
INNER JOIN
field_data_comment_body AS comment_body
ON
comment_body.entity_id=comment.cid
WHERE
taxonomy_forums.taxonomy_forums_tid IN (9);
If you UNION these 2 queries, you'll get the list of posts and comments.
sqlfiddle
To find reference to forum id you must add use of "forum" table (table establishing relationship of nodes to forum terms.)
Also it should be noted that forum id does not exist, it is a taxonomy id.
Here is an example to get only first message topic by taxonomy id(tid)
SELECT * FROM field_data_body fdb
LEFT JOIN forum f ON f.nid = fdb.entity_id
WHERE fdb.bundle="forum" AND f.tid=15
Note that the forum module works with comment core module wich means that only first topic message is stored in "field_data_body" and all replies are stored in "field_data_comment_body" table.
Hope it helps
I have started programming for sometime with PHP using MySQL as the database and I know basic SQL queries upto simple JOINS containing upto two tables.
But the moment I need to get results from 3 or more tables, I am stuck. No matter how hard I try, I still manage to find myself lost. I have searched everywhere looking for a good tutorial on how to tackle complex SQL queries but haven't found anything that explains how to go about it. Most tutorials consists of solutions for a particular problem, but they don't explain the perfect general procedure how to go about tackling a problem
Can anyone explain the basic general way of going about from start to finish, how to construct the query, etc when it comes to complex queries.
For example:
I have a forum with the following database structure:
forumCategory:
id | name | desc
forumTopic:
id | category_id | created_on | created_by | title | content
forumPost:
id | topic_id | created_on | created_by
users:
id | first_name | last_name
All topics are created in the forumTopic table. All replies to that topic are inserted in the forumPost table.
Now on the forum main page, I need to display the categories, the very last post posted by a user in that particular category, the user who posted the last post.
The flow I thought of was :
Find the last post in a category by looking at the MAX(id) in the forumPost table grouped by topic_id. This will get me the ID of the last post in every topic.
Now again find the MAX(of the IDS I got earlier) grouped by category_id. This will get me the last post in every category.
IDs are autoincrementing primary keys.
But I got stuck with constructing a SQL query from the above algorithm
Would be very helpful if someone could help me out on this one.
Get the last post for each category by joining Post to Topic
SELECT category_id , category.name, Max(ForumPost.ID) as maxpostid
from ForumPost
inner join ForumTopic on ForumPost.Topic_ID = ForumTopic.ID
inner join ForumCategory on ForumTopic.Category_Id = ForumCategory.ID
group by category_Id, category.name
(This is an intermediate stage for explanatory purposes - it is included in the query below )
Then join this to the user table to find out the user name (presumably a post has a userid?)
select users.name, lastposts.*
from
forumpost
inner join
(
SELECT category_id , category.name, Max(ForumPost.ID) as maxpostid
from ForumPost
inner join ForumTopic on ForumPost.Topic_ID = ForumTopic.ID
inner join ForumCategory on ForumTopic.Category_Id = ForumCategory.ID
group by category_Id, category.name
) lastposts
on forumpost.id = lastposts.maxpostid
inner join
users on forumpost.userid =users.id
However, you may want to consider updating the category table with the last post each time a post is made. That way you can run a much simpler query for your forum front page.
I have a database of articles, which are stored in categories. For my homepage, I want to grab an article from each category (I don't care which). However, some articles are crossposted to multiple categories, so they come up twice.
I have a table called tblReview with the article fields (reviewID, headline, reviewText) and a table called tblWebsiteContent that tells the site which categories the articles are in (id, reviewID, categoryID) and finally, a table called tblCategories (categoryID, categoryName) which stores the categories.
My query basically joins these tables and uses GROUP BY tblCategory.categoryID. If I try adding 'tblReview.reviewID' into the GROUP BY statement, I end up with hundreds of articles, rather than 22 (the number of categories I have).
I have a feeling this needs a subquery but my test efforts haven't worked (not sure which query needs to contain my joins / field list / where clause etc).
Thanks!
Matt
SELECT T.categoryName, tR.headline, tR.reviewText
FROM (
SELECT tC.categoryName, MAX(tR1.reviewID) reviewID
FROM tblReview tR1 join tblWebsiteContent tWC on tR1.reviewID = tWC.reviewID
join tblCategory tC on tC.categoryID = tWC.categoryID
GROUP BY tC.categoryName) T JOIN
tblReview.tR on tR.reviewID = T.reviewID
this query will select for each category an article headline corresponding to the Max reviewId for that category (you said 'I don't care which')
Try using SELECT DISTINCT. (This will only work if your SELECT is only pulling the article ID.)
select DISTINCT reviewID