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
Related
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.
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'm beginning web development and started using PHP and MySQL. I'm trying to make a CMS similar to a technical blog and stuck at database design. Each post can be of any one of the following type.
Rich text - Single part
Rich text - Multiple parts
Video link - Single part
Video links - Multiple parts
Attachment - Single part
Attachments - Multiple parts
(The attachments can be pdf, doc, ppt)
Each post is under section. The sections are stored in a table. Examples for sections are
Tutorial - all types are allowed
Code snippet - only 1 is allowed
Tips or hacks - only 1,2,3,4 are allowed
News update - only 1 and 3 are allowed
Review - only 1 and 3 are allowed
So my question are
How do I store and distinguish single and multipart posts?
What is the feasible/best way to store attachments?
How do I relate sections and posts? ie., How to know/store that a particular section can support post types(all, only 1, only 1 and 2, etc).
Edit:
By single means, I mean 1 post has only 1 part and by multipart I mean 1 post can have several parts
I guess with "single" you mean that one post is related to one section, multipart means several posts relate to one section?
db-design could be...
table section
---------------
id (int, a-i)
type (int) 1=tutorial, 2=code-snippet etc.
name (varchar)
...
table post
---------------
id (int, a-i)
section_id (int) key to section.id
ordering (int) if multi for controlling which part is first, second etc.
type (int) 1=rich-text, 2=video, 3=attachment <---- drop single/multi discrimination here
single (int) 1=yes, 2=no <---- and put it here instead
content (varchar) --> see below
description (varchar) of this post
note: a single is one post, a multi several post linked to the same section.
where to store attachments:
in the file-system of your web server, the db holding the file-name in table.content.
small post-types (e.g. a link) can be stored directly in table.content
--> keeping your db lean and performing
relating sections and posts:
by post.section_id. Like this, you can link 1 or more posts to a section. use post.ordering to put them in the right order.
section
--------------------------
id | 1
name | "How to build a CMS"
type | 1 (tutorial)
post
--------------------------
id | 1
section_id | 1
ordering | 0
type | 1 (rich-text)
content | "/files/130224_1_1_cms.rtf"
...
id | 2
section_id | 1
ordering | 1
type | 3 (video link)
content | "http://www.youtube.com/hgstersh/showid=23jfjr&blabla"
...
which section.type can have which post.types?
on creating a new section, the section.type is set (e.g. drop-down-list in a form)
on creating a new post for this section, the drop-down-list for post-type offers only permitted types based on section.type, this is done in the php-script with if... or switch...case.
If a post can have multiple images, posts, links that's a one-to-many relationship and the typical schema is:
POST: id, title, ...
RICHTEXT: id, post_id, content
LINK: id, post_id, url
If you need a many-to-many relationship, for example a story can have many links but the same link can be on multiple stories you would have:
POST: id, title, ...
LINK: id, url
POSTS_LINKS: id, post_id, link_id
Also take a quick look at schemas for other popular platforms
I have a news system I'm designing, and it seemed straight-forward at first, but as I've pushed forward with my planned schema I've hit problems... Clearly I haven't thought it through. Can anyone help?
The system requires that the latest 20 news articles be grabbed from the database. It's blog-like in this way. Each article can have sub-articles (usually around 3) that can be accessed from the parent article. The sub-articles are only ever visible when the parent article is visible -- they're not used elsewhere.
The client needs to be able to hide/display news articles (easy), but also change their order, if they desire (harder).
I initially stored the sub-articles in a separate table, but then I realised that the fields were essentially the same: Headline, Copy, Image. So why not just put them all in one big table?
Now I've hit other problems around the ordering. It's Friday evening and my head hurts!
Can anyone offer advice?
Thanks.
Update: People have asked to see my "existing" schema:
articleID *
headline
copy
imageURL
visible
pageOrder
subArticleID *
articleID
headline
copy
imageURL
visible
pageNumber
pageOrder
Will this work? How would I go about letting users change the order? It seemed the wrong way to do it, to me, so I threw this out.
I initially stored the sub-articles in a separate table, but then I realised that the fields were essentially the same: Headline, Copy, Image. So why not just put them all in one big table?
Because referential integrities are not the same.
That is, of course, if you want to restrict the tree to exactly 2 levels. If you want more general data model (even if that means later restricting it at the application level), then go ahead and make a general tree.
This would probably look something like this:
Note how both PARENT_ARTICLE_ID and ORDER are NULL-able (so you can represent a root) and how both comprise the UNIQUE constraint denoted by U1 in the diagram above (so no two articles can be ambiguously ordered under the same parent).
Based on what you've described. I would use two tables. The first table would hold all the articles and sub-articles. The second would tie the articles to their sub-articles.
The first table (call it articles) might have these columns:
+-----------+----------+------+----------+---------+------------+-----------+
| articleID | headline | copy | imageURL | visible | pageNumber | pageOrder |
+-----------+----------+------+----------+---------+------------+-----------+
The second table (call it articleRelationships) might have these columns:
+-----------------+----------------+
| parentArticleID | childArticleID |
+-----------------+----------------+
Not sure if you already accomplish this with the pageNumber column, but if not, you could add a column for something like articleLevel and give it something like a 1 for main articles, 2 for sub-articles of the main one, 3 for sub-articles of a level 2 article, etc. So that way, when selecting the latest 20 articles to be grabbed, you just select from the table where articleLevel = 1.
I'm thinking it would probably also be useful to store a date/time with each article so that you can order by that. As far as any other ordering goes, you'll have to clarify more on that for me to be more help there.
To display them for the user, I would use AJAX. I would first display the latest 20 main articles on the screen, then when the user chooses to view the sub-articles for a particular article, use AJAX to call the database and do a query like this:
SELECT a.articleID, a.headline
FROM articles a
INNER JOIN articleRelationships ar ON a.articleID = ar.childArticleID
WHERE ar.parentArticleID = ? /* ? is the articleID that the user clicked */
ORDER BY articleID
The client needs to be able to hide/display news articles (easy), but
also change their order, if they desire (harder).
On this particular point, you'll need to store client-specific ordering in a table. Exactly how you do this will depend, in part, on how you choose to deal with articles and subarticles. Something along these lines will work for articles.
client_id article_id article_order
--
1 1067 1
1 2340 2
1 87 3
...
You'll probably need to make some adjustments to the table and column names.
create table client_article_order (
client_id integer not null,
article_id integer not null,
article_order integer not null,
primary key (client_id, article_id),
foreign key (client_id) references clients (client_id) on delete cascade,
foreign key (article_id) references articles (article_id) on delete cascade
) engine = innodb;
Although I made article_order an integer, you can make a good case for using other data types instead. You could use float, double, or even varchar(n). Reordering can be troublesome.
If you don't need the client id, you can store the article ordering in the article's table.
But this is sounding more and more like the kind of thing Drupal and Wordpress do right out of the box. Is there a compelling reason to reinvent this wheel?
Create a new field in news(article) table "parent" which will contain news id of parent article. This new field will be used as a connection between articles and sub articles.
As SlideID "owns" SubSlideID, I would use a composite primary key for the second table.
PrimaryKey: slideID, subSlideID
Other index: slideID, pageNumber, pageOrder (Or however they get displayed)
One blog post I prefer to point out about this is http://weblogs.sqlteam.com/jeffs/archive/2007/08/23/composite_primary_keys.aspx as it explains why very nicely.
If you're replying on Auto_Increment, that can be handled too (with MyISAM tables), you can still set subSlideID to auto_increment.
If you're likely to go to a third level then merge - follow Branko above. But it does start to get very complicated, so keep separate for 2 layers only.
I have a table with products that fall under specific categories, but the products within each category can contain multiple meta data tracking field
Table: products
id name category metadata
1 something 1 blue,red,purple
2 something else 2 left,right,middle
I have been trying to contemplate the best method to have a single product table but can't seem to squeeze the metadata in conveniently. for now I have created a table with all the metadata and fields for tracking the related category (the sequence is so i can order them withing a dropdown etc..)
Updated table: products
id name category metadata
1 something 1 1,2,3
2 something else 2 4,5,6
Table: metadata
id category sequence option
1 1 1 blue
2 1 2 red
3 1 3 purple
4 2 1 left
5 2 2 right
6 2 3 middle
If this format makes sense .. I am trying to generate a query that will search for values in my product table and grab each and all of the related meta values. The issue I am having is trying to find a unique value in the products field. if I do a MySQL search for LIKE(%1%) I will get matches for 1, 11, 21, 31 etc ... I thought of adding a leading and trailing comma to the field by default and then search for ",1," which would be unique .. but there has to be a better way ...
Any recommendations (regarding format or query)?
It's not an ideal design to have comma-separated values within a single database field. Aside from the problem you mentioned (difficult to search), your queries will be less efficient, as the DB won't be able to use indices for the lookup.
I'd recommend making a separate table products_metadata with a many-to-one relationship to the products table. Have the *metadata_id*, and the *product_id*, which is a foreign key linking back to the products table. That will make your job much easier.
You want to add another table, which links products to their metadata. It will have two columns: productid and metadataid which refer to the relevant entries in the products and metadata tables respectively. Then you no longer keep metadata in the products table, but JOIN them together as required.