I have the following data which I want to save in my DB (this is used for sending text messages via a 3rd party API)
text_id, text_message, text_time, (array)text_contacts
text_contacts contains a normal array with all the contact_id's
How should I properly store the data in a MySQL database?
I was thinking myself either on 2 ways:
Make the array with contact_id's in a json_encoded (no need for serializing since it's not multi-dimensional) string, and store it in a text field in the DB
Make a second table with the text_id and all contact_id's on a new row..
note: The data stored in the text_contacts array does not need to be changed at any time.
note2: The data is used as individual contact_id to get the phone number from the contact, and check whether the text message has actually been sent.. (with a combination of text_id, and phonenumber)
What is more efficiƫnt, and why?
This is completely dependent upon your expected usage characteristics. If you will have a near-term need to query based upon the contact_ids, then store them independently as in your second solution. If you're storing them for archival purposes, and don't expect them to be used dynamically, you're as well off saving the time and storing them in a JSON string. It's all about the usage.
IMO, go with the second table, mapping text-ids to contact-ids. Will be easier to manipulate than storing all the contacts in one field
This topic will bring in quite a few opinions, but my belief: second table, by all means.
If you ever have a case where you actually need to search by that data, it will not require you to parse it before using it.
It is a heck of a lot easier to debug (for the same reason)
json_encode and json_decode (or equivalent) take far more time than a join does.
Lazy loading is easier, even if not necessary in most cases.
Others will find it more readable and, with a good schema definition, easier to conceptualize and maintain.
Almost all implementations would use one table for storing each text_contacts, and then a second table would use a foreign key to reference the text_contacts table. So, if say you had a table text_contacts that looked like this:
contact_id | name
1 | someone
2 | someone_else
And a text message table that looked like this:
text_id | text_message | text_time | text_contact
1 | "Hey" | 12:48 | 1
2 | "Hey" | 12:48 | 2
Each contact that has been sent a message would have a new entry in the text message table, with the last column referencing the contact_id field of the text_contacts table. This way makes it much easier to retrieve messages by contact, because you can say "select * from text_messages where text_contact = 1" instead of searching through each of the arrays on the single table to find the messages sent by a specific user.
Related
A little overview of the problem.
Let's say I have a table named TableA with fixed properties, PropertyA, PropertyB, PropertyC. This has been enough for your own website needs but then you suddenly have clients that want custom fields on your site.
ClientA wants to add PropertyD and PropertyE.
ClientB wants to add PropertyF and PropertyG.
The catch is these clients don't want each others fields. Now imagine if you get more clients, the solution of just adding nullable fields in TableA will be cumbersome and you will end up with a mess of a table. Or at least I assume that's the case feel free to correct me. Is it better if I just do that?
Now I thought of two solutions. I'm asking if there's a better way to do it since I'm not that confident with the trade offs and their future performance.
Proposed Solution #1
data_id is a not exactly a foreign key but it stores whatever corresponding client property is attached to a table A row. Using client_id as the only foreign key present on both the property table and table A.
It feels like it's an anti pattern of some sorts but I could imagine queries will be easy this way but it requires that the developer knows what property table it should pick from. I'm not sure if many tables is a bad thing.
Proposed Solution #2
I believe it's a bit more elegant and can easily add more fields as necessary. Not to mention these are the only tables I would need for everything else. Just to visualize. I will add the request properties in the properties table like so:
Properties
-------------
1 | PropertyD
2 | PropertyE
3 | PropertyF
4 | PropertyG
And whenever I save any data I would tag all properties whenever they are available like so. For this example I want to save a ClientA stored in the Clients table on id 1.
Property_Mapping
--------------------------------------------------------
property_id | table_a_id | property_value | client_id
--------------------------------------------------------
1 | 1 | PROPERTY_D_VALUE | 1
2 | 1 | PROPERTY_E_VALUE | 1
There are obvious possible complexity of query on this one, I'd imagine but it's more a tradeoff. I intended client_id to be placed on property_mapping just in case clients want the same fields. Any advice?
You've discovered the Entity-Attribute-Value antipattern. It's a terrible idea for a relational database. It makes your queries far more complex, and it takes 4-10x the storage space.
I covered some pros and cons of several alternatives in an old answer on Stack Overflow:
How to design a product table for many kinds of product where each product has many parameters
And in a presentation:
Extensible Data Modeling with MySQL
As an example of the trouble EAV causes, consider how you would respond if one of your clients says that PropertyD must be mandatory (i.e. the equivalent of NOT NULL) and PropertyE must be UNIQUE. Meanwhile, the other client says that PropertyG should be restricted to a finite set of values, so you should either use an ENUM data type, or use a foreign key to a table of allowed values.
But you can't implement any of these constraints using your Properties table, because all the values of all the properties are stored in the same column.
You lose features of relational databases when you use this antipattern, such as data types and constraints.
I have a table called 'Shows' that looks something like this:
| ID | TITLE | IMG | DESC | STATUS |
I also want to store a list of URLs that reference each Show's episode list. Unfortunately, each show can have a vastly different number of episodes, and there's no way to easily predict what the number will be for any show.
How do I store this type of data?
I considered making a table that was named after the ID of each show, with one column that contains the URLs, but I'm sure that the magic of relational databases has some other way of doing this.
Your last comment is on the right track. Yes, you need a separate table to capture the URLs, structured perhaps like:
"URL" table:
| UrlID | EpisodeID | URL |
Where "EpisodeID" is the unique identifier that you called "ID" in your table above. In other words, you might want to rename that "ID" column to "EpisodeID" to make things less confusing down the road.
This way this second "URL" table allows you to store infinite numbers of URLs associated with any single EpisodeID.
Regarding your show vs. episodes question, the same concept applies. You probably want a "Show" table separate from your "Episode" table, and then you'd add a new column to your Episode table that includes the ShowID. That way each row in "Episode" is a child whose "parent" is identified by ShowID.
Or maybe (I can't tell from your question) you expect there will never be more than one URL per episode, so you could get away with just two tables then, Show and Episode, and URL would just be a column in your Episode table.
I have a MySQL table that stores user emails:
user_id | user_phonenumber
----------------------------
id1 | 555-123456789
I want to allow the user to store multiple phonenumbers and I don't want to limit the number of numbers a user can be associated with.
What's the best way of structuring my data, and how would a query work in PDO?
For example, should I store them all in the same field with comma separators and then parse the output when the query is returned, or should I use another table and have each row as a separate number with common user_ids? How would a lookup work then (please provide example code if possible)?
Thanks
Generally RDBMS systems are designed to access fields/rows. Everything will be much harder when you start to break the data-field link/consistency/logic.
I mean when you start to store more data in a single field.
But you know your system's future. It can happen that you won't ever have to access for example the first phone number, and if you can handle it everywhere as a blob then it can be fine to store more values in a single field.
Anyway If this is not a homework or similar short living task then you should choose the 1 phone number/1 record approach.
I mean something like this can be future proof:
create table user_phonenumbers(
id auto_increment primary key.
user_id integer references user(id),
phonenumber varchar(32)
);
Yes, use another table to store user phone numbers.
use inner join to lookup, it would be good.
eI'd like to create custom primary keys in my Access database.
The database is going to be multi-user, so I need a method that ensures each key is unique even when multiple users are trying to add new records to the same tables.
The reason I need to create custom primary keys is because my database starts off an audit trail that goes in to another, external system that I have no control over.
This other system does however allow the use of a single 12-character length user-defined field for us to pass data of our choice through.
I'd like to use that user-defined field to record a 12-character code that has various abbreviations I can extrapolate later (e.g. first 2 characters relate to a department in our organisation, next 3 characters relate to a product and so on...)
From the reading I've done so far, custom keys in Access seems to be something of a minefield.
For my purposes though, I can kind of see at least a compromise in combining Access' autonumber field to essentially help build the primary key I want.
Here's what I was thinking:
The parts of the code that I would want to extrapolate later can be built by our users, so for example, if the Department was Human Resources, the first 2 characters could always be "HR".
Then lets say I let the AutoNumber in access run for a field in the same table in which my "HR" entry was populated... could I get a third field to automatically concatenate the 2 in the same table (not query)...? i.e. like this:
| Department | AutoNumber | CustomPrimaryKey |
| HR | 1 | HR1 |
If that's something that can be done on some event in VBA, then that would be great (show me the code! :))
The second part would be whether I can get the autonumber to concatenate with leading zeros ensuring the "unique number" part of the custom primary key was between 99999 and 00001, i.e. occupying the same 5 character space like this:
| Department | AutoNumber | CustomPrimaryKey |
| HR | 1 | HR00001 |
| HR | 2 | HR00002 |
It is highly unlikely that I would need more than 100,000 entries.
I hope this is possible and safe!
I'd rather leave this as a comment than an answer as I don't think you're totally clear on what you need, but I'll try to answer as best as possible. Also, I'm not going to "Show you the code!" as you suggest as it teaches nothing.
In the first question of automatically concatenating the third field, it's really a question of how the fields are being populated.
If it's through form input, then you can concatenate all of the component fields into the key field during the update events of the controls those component fields are being populated. In VBA you can easily reference members of the record by accessing the form's recordset.
If you're populating the field through a file import where you already have import specs, then you would perform the import excluding your key field, then open the recordset of the table where you imported and iterate through the recordset. You can learn about ADO recordsets here. Again, I'm not just going to write the code because I don't really know what you need this for.
If you're populating the field through your own parser than I probably don't have to explain how to do this.
To your second question, you can easily right align a number in a string using the format() function. For example format(2,"00000") would yield "00002" and format(210,"0000") would yield "0210". You can also make the number of 0s in which you want to align variable using the string() function. For example format(2054,string(12-len("HR"),"0")) would give you "0000002054"
One additional note that I would leave you on is that it's never a good idea to say something like "It is highly unlikely that I would..." and not prepare for it. Murphy's Law is a pain in the B. You should consider handing conditions where you exceed the limit that your key can handle.
I need to extract the following fields into a new table. Any ideas whether I can do this exclusively with a query or I need to use PHP as well?
Current table structure
USERID USEREXPERINCE
1 a:4:{i:0;s:20:"business development";i:1;s:6:"design";i:2;s:9:"marketing";i:3;s:15:"press relations";}
Required table structure
USERID USEREXPERINCE
1 business development
1 design
1 marketing
1 press relations
2 web development
2 design
3 marketing
3 business development
Thanks.
You need to use PHP - the 'LONGTEXT' data is in fact a serialized PHP array.
Execute the following to see what I mean:
<?php
print_r(unserialize('a:4:{i:0;s:20:"business development";i:1;s:6:"design";i:2;s:9:"marketing";i:3;s:15:"press relations";}'));
?>
As such, the easiest thing to do would be to read each row from the database, unserialize the data and insert it into a new table with the required fields. (I'm guessing you need to search on these, hence the need to store them as dedicated fields.)
That said, the serialized string you provided only appears to be storing IDs -> Field names (rather than any values), so I'm not sure what's going on there.
I would use PHP for this, simply because it is easier to call unserialize() and generate new INSERT statements than to parse the string in a MySQL procedure (though that could also be done). Also beware if your USERID column is currently a primary key, since it cannot be with the new structure.