I have a small blog project
I have 3 tables
Posts
PostID | TITLE | WRITERS(USERS) | CATEGORIES
1 | SOME TITLE | 1,2 | 1,2
USERS
USERID | USERNAME
1 | Alaa
2 | John
Categories
1 | Business
2 | Marketing
I am trying to get this output
POST TITLE: SOME TITLE
Writers: Alaa And John
Categories: Business, And marketing
Please note that i am talking about a very big loop, 100 post in a page for many viewers
So, currently i have two ideas
First idea
1- take value from writers ( 1,2 )
2- Explode it by php
3- use mysql query to bring the writers
4- Do the same thing for categories
Second idea is to remove the columns writers, categories from the posts table and create a fourth table and call it connections, which will refer ids to each others ( connect everything together )
But i don't even know if i can do the mysql query
You can get all these values in one MySQL query.
SELECT p.TITLE AS `Post Title`,
GROUP_CONCAT(DISTINCT u.USERNAME) AS Writers,
GROUP_CONCAT(DISTINCT c.CategoryName) AS Categories
FROM Posts p
JOIN Users u ON FIND_IN_SET(u.USERID, p.WRITERS)
JOIN Categories c ON FIND_IN_SET(c.Id, p.CATEGORIES)
GROUP BY p.TITLE
Output:
Post Title Writers Categories
SOME TITLE Alaa,John Business,Marketing
Demo on dbfiddle
Note: storing values in comma separated lists (e.g. your WRITERS and CATEGORIES columns) is a bad idea and makes writing this sort of query problematic (it's only MySQL's FIND_IN_SET function which makes it workable at all) and you should look into properly normalising your data (one value per row). Here is an example of how your database could look normalised.
Related
I am going to make a website and before that I am going to make a database table. The problem is how to do it correctly. Sorry, but I am new to PHP and Mysql. I only have a definite number of categories, so this is my DB view:
--------------------
Video_name Varchar
Video_loc Varchar
cat1 Boolean
cat2 Boolean
cat3 Boolean
cat4 Boolean
cat5 Boolean
cat6 Boolean
cat7 Boolean
--------------------
I kept it like this because 1 video might belong to 2 or more categories. But it will take a lot of space in long term. If a video belongs to cat2 & cat5 then the boolean will have the value "1". But others will also have the value "0" and this is a waste of space.
How can I do it the right way? BTW I have seen Wordpress, it gives the categories a unique ID then on the main table it specifies multiple ids for multiple categories like e.g.: it keeps it like:
-----------------------
id | title | category |
1 | Lorem | 2,4,8,16 |
2 | Epsum | 2,9,8,20 |
3 | Losum | 2,4,9,5 |
4 | Eprum | 2,10,8,1 |
-----------------------
I don't get how it did it like that. Can anyone tell me how to do it like this or any better idea than mine?
Generally it is a "no no" to store structured data within a single column in a table. The Wordpress example does exactly that; it stores a comma separated list of categories in the category column. For that reason I would not recommend using that schema.
The "right" way to do this is to have a table for videos and another table for categories. The relationship between videos and categories is managed by a third table which maps the video to a category and vice versa. There will be multiple entries in this video-to-category table - one for each category that a video can be assigned. Something like this:
table: video
----------------
id int
name varchar
location varchar
----------------
table: category
----------------
id int
name varchar
----------------
table: video_category
---------------------
video_id int
category_id int
---------------------
Another way would be to use a bit field for the categories. Your video table would then have just a single column for all categories with bits set to 1 for those categories to which the video belongs, and 0 for those that it does not. This is an option if storage space is very important to you, however, it is less flexible than using 3 tables, and I recommend the latter approach.
Generally you use a 3rd table with the relationship between the video and category. So you'd have a categories_videos table which has id, category_id, and video id
You can do joins to get all categories related to material, but this is more advanced MySQL. Either start reading the MySQL documentation or pickup a framework that helps you with all this and makes it easier, I always recommend Cakephp.
I have two table
one table is alldata ( here info_id is a text field data inserted using php )
=================
id | info_id
=================
1 | 2, 3, 5, 9
2 |
=================
second table is info
=================
id | name
=================
1 | one
2 | two
3 | three
4 | four
5 | five
6 | six
7 | seven
9 | eight
9 | nine
=================
now I want to select list of data from table two where data id will be matched with table one first item info_id data
my query is
SELECT i.* FROM `info` as i,`alldata` as a where i.id IN(a.info_id) and a.id=1
my query works but select only one item from table two.But there are multiple matched.
You have a very poor database design. First, storing numeric ids as strings is a bad idea -- numbers should be stored as numbers. Second, SQL offers this great data structure for storing lists. It is called a table, not a string.
You should really have a junction table, one one row per id and info_id.
That said, sometimes we a struck with substandard data structure. MySQL offers support for this. You can use:
SELECT i.*
FROM `info` i JOIN
`alldata` a
ON FIND_IN_SET(i.id, REPLACE(a.info_id, ', ', ',') ) > 0
WHERE a.id = 1;
You should also learn to use proper, explicit join syntax. If you use this method, instead of fixing the database design, you are not allowed to complain about performance. MySQL cannot take advantage of things like indexes to improve the performance of this type of query.
Although I researched on this topic and came across a few solutions like using JOIN LEFT or subqueries, I am still unable to get the result I want as I am not strong in mySQL. I am more of a web designer trying to use simple php to my website better for a school project.
I am trying to create a web application something similar to a blog. I wanted to count how many comments are there for a post and display the number for my users to see, but if there is no comment for that row, my query will return nothing instead of 0.
This is my query below:
SELECT post.post_id, COUNT(comment)
FROM `comment`, post
WHERE `comment`.post_id = post.post_id
GROUP BY post.post_id
The result:
Record | post_id | COUNT(comment)
1 | 12 | 2
2 | 13 | 1
3 | 15 | 1
4 | 16 | 1
As you can see, post_id 14 has no comments, thus my query returns nothing. What must I do to make my result looks like this?
Record | post_id | COUNT(comment)
1 | 12 | 2
2 | 13 | 1
3 | 14 | 0
4 | 15 | 1
5 | 16 | 1
Also, it would be nice of you guys to give me references or links to understand the concept behind the solution as I want to learn more about php :)
So Actually when you do that (which is what you do, reformulated for the JOIN):
SELECT post.post_id, COUNT(comment)
FROM `comment`
INNER JOIN post ON `comment`.post_id = post.post_id
GROUP BY post.post_id;
You gather only post rows having at least one reference in comment.
If you alter the JOIN type to a LEFT join, this way:
SELECT post.post_id, COUNT(comment)
FROM `comment`
LEFT JOIN post ON `comment`.post_id = post.post_id
GROUP BY post.post_id;
Then the rows from post are all there, and NULL values are inserted for columns of comments if no comments related to this row exists (that's a left join). So if comment is a column from table comment it will be there for each rows of post table, but with a NULL value, after the group by on the post_id column the subset of comments related to this post contains only 1 NULL value, the count should return 0.
select count(NULL);
returns 0.
Now you could use a subquery but that's a really bad idea, subqueries are usually done instead of LEFT JOINS, usually it's a mistake, sometimes it's not, but it's really often a mistake. When you do a left join indexes are used to compare the key values of the 2 tables (the ON clause) and build one final 'temporary' result of rows, mixing values from both tables (and then, or maybe in the same time, the filters from other parts of your queries are applied). When you use a subquery, for each row of the first table a new query is run to get results from the second table (not always, but it's another problem), the cost is reeeaaally bigger for the database engine.
Query the post table and do a subquery for the count on the comments query.
SELECT post.post_id, (SELECT COUNT(comment) FROM `comment` WHERE `comment`.post_id = post.post_id) as comments FROM post
This may get extremely slow with lots or rows so add a limit with a pager when you get to that point.
I am working on a blog. Now I want to display the most used tags of an author. The tags are stored in the articles table, in a column called tags, komma seperated:
Article table (id | authorid | tags):
1 | 1 | soccer, sport
2 | 1 | sport, tennis, injury
3 | 1 | sport, golf, injury
So I want to display author with id 1 and display his 3 most used tags (from the article table as displayed above). In this case that would be: sport, injury, soccer.
Is this possible in MySql?
Yes its possible, but the better answer would be to direct you into a more "Normal" database structure.
You really need a db set up like:
Table of articles, table of tags, table of article_tags containing the IDs of the tag and the article it's assigned to.
You can then query the tags by each article ('X') by looking in article_tags and returning all tag_id's where article_id = ('X').
You should take a look at database normalization -- the wikipedia article is very advanced however it will give you terminology which you can search for to find more articles on the topic.
The basic idea is you'll have another table:
table name: tags
columns: id | name
And then a table to join them:
table name: article_tags
columns: article_id | tag_id
Then you'll join all of the data together in a query in order to display the tag names for each article. It will then be possible to do more advanced queries on the tables to figure out things such as most used tag by article, and most used tag by author.
I'm new to database structure. I'm trying to create an app that allows users to like certain entries, but I want to be able to tie likes to users so that I can change the visuals before/after the like action.
I think from research that I should have an 'entries' and 'users' table and then have a 'likes' table that ties the two to each other.
The only thing I'm unsure of is, when getting and displaying the contents... how would I write the queries? If I query for all the entries I need, do I then go back and individually query each to see if it has a like tied to it for the current user? That seems like it might be a costly operation. Is there a more efficient way?
Hope that makes sense,
Thanks.
I think you have the right database design in mind. As far as queries are concerned, assume tables as such:
Users
ID | Name
1 | Bob
2 | Sally
Entries
ID | Name
1 | Red
2 | Blue
3 | Yellow
Likes
UserID | EntryID
1 | 1
1 | 2
2 | 2
2 | 3
So we can say Bob likes Red and Blue while Sally likes Blue and Yellow. So a query to retrieve all entries, plus an indicator of what Bob likes would be:
SELECT
e.ID,
e.Name,
l.UserID
FROM Entries e LEFT JOIN Likes l ON l.EntryID = e.ID
WHERE l.UserID = 1 -- Bob's User ID
ORDER BY e.Name
This would return
ID | Name | UserID
2 | Blue | 1
1 | Red | NULL
3 | Yellow | 1
The UserID column indicates if Bob likes the entry or not - a NULL is No and a value is Yes.
Assuming you have a table Entries with a column entity_id (and whatever else you store about the entity) and a second table UserLikes that contains the columns user_id and entity_id, you would do the following:
SELECT Entries.col1, Entries.col1 . . ., UserLikes.user_id
FROM Entries LEFT OUTER JOIN UserLikes ON
Entries.entity_id = UserLikes.entity_id
WHERE UserLikes.user_id = :user_id
AND Entity.col_whatever = :whatever
In this example, Entries.col1, Entries.col2 . . . is the list of columns you want to get back about the Entries. The :user_id is a parameter that contains the id of the user you're currently trying to display Entries for. And the last line is standing in for whatever limitations you want to put on the Entries are returned.
This query will give you a row for each Entry you searched for. You can check the value the returned column user_id. If it's NULL then it was not liked by the user, if it contains the user's id, it was liked by the user.
I think u can retrieve the entries and query the likes table at the same time to get if the current user likes the entry performing a stored procedure. So u can control the value of the set of data returned by the query for example returning one colum for the entry text and one boolean column to evaluates the current user likes... In this way you will at least one parameter for the stored procedure to indicate who is the current user
I hope this idea help u...