I'm developing a site with Laravel 4.2. I have two tables: articles and tags.
This is my tags table:
id | article_ids | xxxx
2 | 2,41,23,6 | xxxx
I'm using Eloquent and I want to find an specific id in article_ids column.
How can I do this?
Can I search in MySQL like this?
Thanks for helping. Sorry for my bad English.
Pretty much everything has been already said - bad design and you should avoid it and so on and so forth. That's true, I agree.
Do it the right way. However, here's how it's done in MySQL:
// say you want tags related to articles 2 and 23
SELECT * FROM tags
WHERE FIND_IN_SET('2', article_ids)
AND FIND_IN_SET('23', article_ids);
// Eloquent
Tag::whereRaw(
'find_in_set(?, article_ids) and find_in_set(?, article_ids)',
[$id1, $id2] // bindings array
)->get();
This is a very bad way of associating tags with articles, as you've just discovered, because it cannot be easily queried against. Instead, for a many-to-many relationship between the two, you'll want an intermediate table with columns article_id and tag_id. For an article with four tags, there'd be four records, one for each association.
Related
Im building a yellow pages site. I tried multiple database structures. Im not sure which one is best. Here are few I considered,
Saving all business data - name, phone, email etc in one table, list of tags in another, and mapping data id and tag id for tag-data relationship in a third table. I found this cumbersome since I'll be doing most things directly in the database (at least initially, before launch) and hence distributing everything can be problematic in my case. This one is a clean solution I must admit though.
Saving biz entries in one table with a separate column for tags (that'll contain comma separated(or JSON) tags for every entry). Then retrieving results using like query or full-text search for a tag. This one will be slower and will get more slow as db size increases. Also its not easy to maintain - suppose if I have to rename a tag.
(My Preferred Choice) Distributing biz data in different tables based on type - all banks in one, hotels, restaurants etc in separate tables. A separate table for all tags containing a rule for searching data from the table. Here is a detailed explanation.
Biz Tables:
college_tbl, bank_tbl, hotel_tbl, restaurant_tbl...so on
Tags Table
ID | Biz Table | Tag Name | Tag Key | Match Rule (col:like_query_part)
1 | bank_tbl | Citi Bank Branches | ['citi','bank'] | 'name:%$1%$2%'
2 | restaurant_tbl | Pizza Hut Restaurants | ['pizza','hut'] | 'name:%$1%$2%'
3 | hotel_tbl | The Leela Hotels | ['the leela'] | 'name:%$1%'
I'll then use 'Match rule' in like query to fetch results from 'Biz Table' for 'Tag Name'.
Im going forward with the third approach. I feel its simple, reduces the need of third data-tag relationship table, renaming is easy and performance won't get down if table has limited entries - say 1 million max per table.
Im scratching my head for the last 15 days to find the best structure and feel this one is pretty good in my case.
Please suggest a better approach or if this approach could have some issues later on.
Use Number 1. Period, full stop.
The mistake is "doing things directly in the database" rather than developing the API first.
Number 2 has one advantage -- FULLTEXT search. That can be tacked onto #1 after you have have a working API and some data to play with.
Number 3 (multiple similar tables) is a fisaco. Numerous Q&A ask about such; the reply is always "NO".
I'm making a blog system and I want to add 'tags' to my blogposts. These are similar to the tags you see here, they can be used to group posts with similar subjects.
I want to store the tags in the database as a comma-separated string of words (non-whitespaced strings). But I'm not quite sure how I would search for all posts containing tag A and tag B.
I don't like a simple solution that works with a small database where I retrieve all data and scan it with a PHP loop, because this won't work with a large database (hundreds if not thousands of posts). I do not intend to make this many blogposts, but I want the system to be solid and save worktime on the PHP scripts by getting right results straight from the database.
Let's say my table looks like this (it's a bit more complex actually)
blogposts:
id | title | content_html | tags
0 | "hello world" | "<em>hello world!</em>" | "hello,world,tag0"
1 | "bye world" | "<strong>bye world!</strong>" | "bye,world,tag1,tag2"
2 | "hello you" | "hello you! :>" | "hello,tag3,you"
How would I be able to select all posts that contain "hello" as well as "world" in the tags? I know about the LIKE statement, where you can search for substrings, but can you use it with multiple substrings?
You can't index a field of csv values in a meaningful way, and SQL doesn't support being able to find a unique value in a field of CSV values. Instead, you'll want to set up two more tables, and make the following alteration to your table.
blogposts:
id | title | content_html
tags:
id | tag_name
taxonomy table:
id | blogpost_id | tag_id
When you add a tag to a blog post, you will insert a new record into the taxonomy table. When you query for data, you'll join across all three tables to get the information similar to this:
SELECT `tag_name` FROM `blogposts` INNER JOIN `blogposts_taxonomy` ON
`blogposts`.`id`=`blogposts_taxonomy`.`blogpost_id` INNER JOIN `blogpost_tags` ON
`blogposts_taxonomy`.`tag_id`=`blogpost_tags`.`id` WHERE `blogposts`.`id` = someID;
//UPDATE
Setting up the N:M relationship gives you a lot of options during the build out of your application. For example, say you wanted to be able to search for blogposts that were all tagged "php." You could do that as follows:
SELECT `id`,`html_content` FROM `blogposts` INNER JOIN `blogposts_taxonomy` ON
`blogposts`.`id`=`blogposts_taxonomy`.`blogpost_id` INNER JOIN `blogposts_tags` ON
`blogposts_taxonomy`.`tag_id`=`blogposts_tags`.`id` WHERE `blogposts_tags`.`tag_name`="php";
That will return all blogposts that have been tagged with the "php" tag.
Cheers
If you really wanted to store the data like this the FIND_IN_SET mysql function would be your friend.
Have the function twice in the where clause.
But it will perform horribly - having a linked table one-to-many style as already suggested is MUCH better idea. If you have lots of the same tags a many-to-many could be used. Via a 'post2tag' table.
I am designing a blog site in php where users can add manually related posts to a post.
I thought to use an autoincrement integer for all posts related.
This is the table:
Blog:
-id
-related ( it's 0 if there aren't related posts or it contain an autoincremet integer that it is the same for all posts related )
-id_user
-title
-body
-date
I prefer not to use a "related table" if possible to avoid complex queries.
So I need a way to get an auto increment integer in this case or you can suggest me other solutions :)
Why not have a second table? It's probably the most robust solution, and it doesn't complify your queries much at all.
You should have a second table, related-posts, with two fields: original and related.
Neither are unique, so the following is possible (assuming 1,2,3,4 are post IDs)
o | r
--+--
1 | 2
1 | 3
2 | 3
2 | 4
4 | 1
When you need to find posts related to post 1 (for example), you query
SELECT `related` FROM `related-posts` WHERE `original` = 1;
This will give you all related post IDs.
This kind of relationship is called many-to-many relationship, one post can have many related posts, and one post can be related to many original posts.
You can just set related as NULL, and after that you can check, whether it's NULL — then there is no related posts.
To select all related posts:
SELECT * FROM Blog where related=:blog_id
I am developing a web application where users can create the following resources/contents:
Events | Music | Posts | Classifieds
They have alot of fields in common, such as:
created_date | title | desc | user_id
Now I am wondering if I should create separate tables for each content, or save them all in one table, with a type_id foreign key, which points to a content_type table. Ofcourse, some distinct fields will be there which will be only used by specific content types, for those not using those fields, I can just leave it blank.
Data looks more organized with separate tables for each content type, but searching for a keyword across all tables is becoming a nightmare(with joins, unions etc). If it was just a single table, searching will be very easy.
I need that the user be able to search across all content with a keyword. He would also be able to search specific contents, for that I will do a WHERE clause on the type_id field.
I am not aware of all the pros/cons of each method, but I would appreciate if people could advice me so that I don't make the wrong decision, and have to redo everything from start.
maybe think of using the "has a" relationship. For instance, an event "has a" "web item handle" attached to it, and a "web item handle" is a thing with description, created date, title, 'owner' etc...
Unless they truly have identical data, I would use separate tables. Having one table with some fields only used by specific content types is really not very good database design.
If you really want one table with the basic data, you could create one as you suggested with a content_type and the common fields, and then have 4 separate tables for each of the types with the other distinct fields, then do an inner join when you select the fields for that type. But personally I think you are better off just creating 4 tables.
Let's say I have 10 books, each book has assigned some categories (ex. :php, programming, cooking, cookies etc).
After storing this data in a DB I want to search the books that match some categories, and also output the matched categories for each pair of books.
What would be the best approach for a fast and easy to code search:
1) Make a column with all categories for each book, the book rows would be unique (categs separated by comma in each row ) -> denormalisation from 1NF
2) Make a column with only 1 category in each row and multiple rows per book
I think it is easier for other queries if I store the categories 1 by 1 (method 2), but harder for that specific type of search. Is this correct?
I am using PHP and MySQL.
PPS : I know multi relational design, I prefer not joining every time the tables. I'm using different connection for some tables but that's not the problem. I'm asking what's the best approach for a db design for this type of search: a user type cooking, cookies, potatoes and I want to output pairs of books that have 1,2 more or all matched categs. I'm looking for a fast query, or php matching technique for this thing... Tell me your pint of view. Hope I'm understood
Use method 2 -- multiple rows per book, storing one category per row. It's the only way to make searching for a given category easy.
This design avoids repeating groups within a column, so it's good for First Normal Form.
But it's not just an academic exercise, it's a practical design that is good for all sorts of things. See my answer to Is storing a comma separated list in a database column really that bad?
What you want to do is have one table for books, one table for categories, and one table for connecting books and categories. Something like this:
books
book_id | title | etc
categories
category_id | title | etc
book_categories
book_id | category_id
This is called a many-to-many relationship. You should probably google it to learn more.
This relationship is a Many-To-Many (a book can have multiple categories and a category can be used in several books).
Then we have the following:
Got it?
=]
I would recommend approach number 2. This is because approach 1 requires a full text search of the category column.
You may have some success by splitting it up into two tables: One table has one line per book and a unique id (call the table books), and the other has one line per book per category and references the book id from the first table (call the table bookcategories). Then if you only need book data you use table books, where if you need categories you join both tables.