Denormalizing table afterwards query - php

So far I had my downloads table denormalized. I had two fields - author and country. They were separated by a space, e.g.: Jack James as for author and us uk for country.
I decided it's time to normalize it so I made a new table called downloads_authors with fields (da_id, downloads_id, da_author, da_country) and now I have:
+-----+------------+---------+----------+
|da_id|downloads_id|da_author|da_country|
+-----+------------+---------+----------+
|1 |1 |Jack |us |
+-----+------------+---------+----------+
|2 |1 |James |uk |
+-----+------------+---------+----------+
So far so good.. but in the way I used to have them, I used explode and with a very bad function, I was getting the desired result - <flag img> Jack, <flag img> James
Now, when I have them in another table I cannot think of a way to do this:
SELECT * FROM downloads and list the respective author(s) without having an inner loop (because if I do a JOIN then I will have the information from downloads again and again).
Desired otuput is:
item
- author
item
- author
- author
Am I wrong about the JOIN and is it the way to go?

Your options are join and use the download information the first time you get a new download id and ignore the download information until you get a new download id. Or do what I said, query the data out and loop to build a new array. Or you could also use group_concat to join the authors together back into a single string.
I would just query out all downloads then query out all authors. Loop over the downloads and assign them to an array where the download id is the key. Then loop over the authors and assign the different authors to a sub-array of the downloads using the download id.

Related

How to store variable length arrays in a database

I'm looking for a way to save data based off a set of rows in another table, but I don't know how to set up the field. Think something similar to using the results of a mysql group_concat as the field. The data is based off the unique combination of rows, rather than one row or field.
What I need to be able to do is:
Store the array itself in the database
Store associated data about the array
Retreive the array
The ability to lookup data about the array using the data in the array
Some options I've thought about:
Saving as an ordered set concatenated into a string.
Saving the serialized array (serialized using php's serialize function).
Saving the set as a hashed string using a reversible hash.
None of these options seem correct so I came here hoping someone has a better answer.
Background:
Supposed I have the following tables:
users {id, other unimportant fields}
products {id, other unimportant fields}
shipments {id, user_id, product_id, date, other unimportant fields}
I want to create a new table called assigned_products where the assigned product is based off of the unique combination of products they've received in the past. So assigned_products should look like:
assigned_products {set_of_products_received (array), product_id (data about the array)}
I don't know of a good way to store set_of_products_received in a database.
Example use:
Suppose I have 100 users who got product A, 100 users who got product B, and 100 users who got products A and B. Suppose then I wanted to give product B to everyone who got product A, product A to everyone who got product B, and product C to everyone who got product A and B. The assigned products table should look like:
+--------------------------+------------+
| set_of_products_received | product_id |
+--------------------------+------------+
| A | B |
| B | A |
| A, B | C |
+--------------------------+------------+
I'm just looking for a better way of storing set_of_products_received
Reading this over I realize it's a bit hard to understand, but I don't really know the appropriate terms to describe this issue (probably why I'm having trouble finding solutions). I'll be happy to clarify if anyone has any questions.

Storing a list of songs linked to event mysql

I have a database in MySQL that currently lists approximately 1500 concerts and events. Now, the plan is to add setlists (list of the songs performed at the concerts) for all the concerts in the database. Basically this will mean a lot of repeated values (songs performed at many concerts), and I would really appriciate some input on what the best approach would be.
I initially started out with a database similar to this;
| eventID | edate | venue | city | setlist |
The field setlist was basically text data, where I could paste the list of songs and parse through it to put each song on a new line with php. This works, and editing the text and running order was like editing a text document. Now, obviously this was pretty simple, but has drawbacks and limitations. Simple things like getting stats on songs performed is probably very difficult, right?
So, what is the best way to store the setlist value?
Create a new table that adds a new row for each song performed, and that has a foreign key linking to eventID? How would I best retain (and edit, if needed) the running order of the songs in that table? Any other suggestions?
Thanks for any input or advice on this, as I would love to get some help before I start adding all the data.
I would create a table that holds each song performed at a specific event:
| songId | eventID | song |
Where eventID can be duplicated in multiple rows to show each song performed at that event.
This way you can query all the times a specific song was performed, and also get all songs (the setlist) for a specific event by querying on the eventID.

PHP/MySQL blog system

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.

Have an array in a SQL field. How to display it systematically?

I have a field in a data feed coming in with some values separated by commas. For one record, the values are:
A06,C05,C06,C15,C18,C19,C21,C22,E05,E22,G11,J02,J07,L04,L07,M01,M05,N03,N07,N10,N11,N12,N18,N19,N20,N24,O02,O03,O04,O06,O09,O14,O15,O16,O20,O21,O31,Q01,Q04,Q08,R07,S08,T08,T12,T23,T32,U01,U03,U04,U06,U13,W09,W11,W16,W19,W30,W45,X02,X03,X12,Z07
I have a separate table with some descriptions as to what each code means. When I query the main table and get this field name as a value, I can use explode to get it into an array and use a foreach loop to output each value.
The problem is, I want to display the description stored in another table. What's the proper way of iterating through this to display these values in a list?
As an example, C21 means "Gated Community."
You can use FIND_IN_SET() function for that.
Example you have record like this
Orders Table
------------------------------------
OrderID | attachedCompanyIDs
------------------------------------
1 1,2,3 -- comma separated values
2 2,4
and
Company Table
--------------------------------------
CompanyID | name
--------------------------------------
1 Company 1
2 Another Company
3 StackOverflow
4 Nothing
Using the function
SELECT name
FROM orders, company
WHERE orderID = 1 AND FIND_IN_SET(companyID, attachedCompanyIDs)
will result
name
---------------
Company 1
Another Company
StackOverflow
As you have tagged codeigniter you could use the built in Active Record's method $this->db->where_in(); to get the description. For example consider the code below
$codes = array('A06', 'C05', 'C06');
$this->db->where_in('description', $codes);
// Produces: WHERE codes IN ('A06', 'C05', 'C06')
For more information about Active Records of Codeigniter refer Active Record Class
For more information on how mysql WHERE IN works refer Tutorial
Just for follow the books, the best way of doing this in SQL language is to use the relationship.
For understand this I recommend you read this simple paper http://net.tutsplus.com/tutorials/databases/sql-for-beginners-part-3-database-relationships/
and maybe this http://www.informit.com/articles/article.aspx?p=30875&seqNum=5 for SELECT the data, or search for yourself on the web, and I recommend you to try yourself the examples. SQL Relationship Is good and necessary for security and many others reasons.

Aggregating many user created items into one "general" item

I'm building a site where users can inventory items and apply various attributes to it, eg. photos, urls, comments, etc.
I have a database structure of three tables:
users, entries, associations.
The tables have the following fields:
users
id | joined | email | salt | password
entries
id | created | creator | type | value
associations
id | created | creator | type | node1 | node2
Here's a breakdown of the site function:
Users adding items to their inventory
All user-created items go in entries with a type of 'item'. A row is added to associations with type 'possession', node1 users.id and node2 entries.id. This associations row is how I would (using INNER JOIN entries) pull and display a user's inventory (not just pulling all entries where creator = users.id, because a user may create an item they don't own).
Adding attributes to items
This part is what seems to throw off everyone I explain things to. An "attribute" is really just another item. In this way, it basically renders a user-created free-form hierarchy. E.g., You may 'tag' For Whom The Bell Tolls with "Book", and Book is another item (whether or not it's in the user's inventory matters not). To makes this work, I just add another row to the associations table with type 'tag' and node1 entries.id (parent item) and node2 entries.id ('tag' or child item). Remember than an entry may also be a url, comment, photo, etc, it would just depend on entries.type. Now I can pull all an items attributes. Eg, all photos: ($item_id = page I'm looking at) "SELECT * FROM entries INNER JOIN associations ON associations.node1 = $item_id AND associations.node2 = entries.id AND entries.type = 'photo'.
I can use a similar query to pull all an item's comments, it's url, whatever. This allows me to create a fluid system of associations between items, items and their owners, items and comments, comments and comments (replies).
My question is, once I have many user created entries of an item eg., "MacBook", what would be the best way to merge, aggregate, amalgamate or however else you like to call it, all those individual items into one general item, so that all these pieces of data created by users can be one knowledge chunk, if you will.
Again, I'm not so worried about users entering "mac book" "Apple Macbook" etc. En masse, those users are just doing it wrong and won't effect the community.
Basically, if a user that didn't own "MacBook" did a search and landed on the MacBook page, they would see the most popular tags, some photos (random, popular, whatever, that's trivial), comments about it, most popular URL, etc.
Also, thanks so much for taking time to read my confusing and elaborate description! :)
Have a table called "Tags", which would have a unique Name field. Whenever a user enters a new Name, it's added there.
Every Item should be linked to that table. This sounds like a many items to one tag arrangement, so you wouldn't need an Item_Tags table, just a foreign key Tag_Id in the Items table.
For Comments, you just have a Comments table which links to that table.
To display only 4 photos, you do a SELECT of photos that are joined to that name (presumably, they're photos of Items that have that Name) and LIMIT 4
For other/similar design patterns, do a search for questions related to tags, like this one.

Categories