i am looking for someone who can help me to achieve a way to store multiple images as a group in mysql.
Basically a user will upload multiple images for example 3 as a group (1 POST), how can i store them in the database.
This is how i store images right now.
+-------------+------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+------------------+------+-----+-------------------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| userid | int(11) | NO | | NULL | |
| uploaded_at | datetime | YES | | CURRENT_TIMESTAMP | |
| path | varchar(255) | NO | | NULL | |
| is_grouped | int(11) | YES | | 0 | |
| grouped_to | int(11) | YES | | 0 | |
+-------------+------------------+------+-----+-------------------+----------------+
'is_grouped' ( 0 or 1 ) & 'grouped_to' ( id of main image ) are what i though could work but caused problems while retrieving from mysql database.
Any help would be appreciated.
I don't know what exact problem you are having with your current approach, but I would suggest just using the following definition for the images table:
images (id, user_id, uploaded_at, path)
Then, create a junction table which relates images to their groups:
image_groups (image_id, group_id)
We don't really need the is_grouped column any more, because we can simply check image_groups to see if the image appears in a group and/or if that group has more than one image. Similarly, the grouped_to column has now been made redundant because the junction table stores this information. Note that you might also want to have a groups table, which could store some metadata about each image group, such as the name, time of creation, etc.
Related
I have two tables here. One is Items and other is Parts.
Items have a part_id and Parts have an item_id.
When a user press on the submit button from the ItemDetail view, data are sent to the server and inserted into those two tables.
Here is how my code works :
Insert to Items table first and get the id of new Item data
Insert to Parts table with this item_id and other Part data
Update to Items table using new part_id
But can I write those three SQL requests in just one request ?
Here is the structure of my tables:
Items
Field | Type | Null | Key | Default | Extra |
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| price | int(11) | YES | | NULL | |
| part_id | int(10) unsigned | YES | | NULL | |
| type | varchar(255) | YES | | NULL | |
Parts
Field | Type | Null | Key | Default | Extra |
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| item_id | int(10) unsigned | NO | | NULL | |
| name | varchar(255) | NO | | NULL | |
| number | varchar(255) | YES | | NULL | |
You shouldn't have 2 tables pointing to each other like this, only one of the tables should have a foreign key, not both.
Then what you are looking for is this: http://dev.mysql.com/doc/refman/5.7/en/commit.html
Transactions make sure that either all queries are executed, or if there is an error somewhere all changes will be reverted.
Looking at the logic you are using, you are doing it correctly.
As they are two separate tables you will need to do two separate insert statements in SQL. Of course you can use a stored procedure so that you only need to call one item in your code and the SP will do two inserts.
A question here is what code are you using? If you are using something like entity framework and your relationships are defined between your elements such as
Items
-Field 1
-Parts (FK) List<Parts>
That would work, but looking at what you have tagged I am guessing your not using a ASP language?? If you are let me know and I may have a better solution for you.
I guess that this is somewhat of a philosophical question. I need to collect pathology results for a group of patients and store them in a database. In the past I have used a very simple table structure (simplified):
+-------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+-------+
| ID | bigint(20) | NO | PRI | NULL | |
| Updated | datetime | NO | PRI | NULL | |
| PatientId | varchar(255) | NO | | NULL | |
| Name | varchar(255) | NO | | NULL | |
| Value | varchar(255) | NO | | NULL | |
+-------------------+--------------+------+-----+---------+-------+
More often in schema design I see:
+-------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+-------+
| ID | bigint(20) | NO | PRI | NULL | |
| PatientId | varchar(255) | NO | | NULL | |
| Ph_Value | varchar(255) | NO | | NULL | |
| K_Value | varchar(255) | NO | | NULL | |
| Ca_Value | varchar(255) | NO | | NULL | |
| Ph_Value_updated | datetime | NO | | NULL | |
| K_Value_updated | datetime | NO | | NULL | |
| Ca_Value_updated | datetime | NO | | NULL | |
+-------------------+--------------+------+-----+---------+-------+
It seems to me that the first design is much more flexible, expandable etc. However, I do wonder about performance hits when the records run to the millions.
The issue with the second is that there may be a couple of hundred fields that need to be recorded on occasions.
I would be really interested to get comments / advice / guidance on this.
You are absolutely right, the first schema is a lot more flexible: you can add new keys on a live database without changing the schema. However, flexibility is usually bought with the time and/or the space. In this case, it's both: you need more space to store all keys for the same row because the ID is replicated N times, and the joins or orderings required to get the fields together would take time.
There is no reason to pay for flexibility unless you need it. If most of your queries need most of the columns, the second result is the most economical. However, if most of your queries ask for a single column, getting the flexibility may be worth spending the CPU time and the database space.
In my opinion, If that name/value pairs won't be changed much so the second option is much better in the terms of space and number of rows.
Also you can have another solution to optimize the first schema , to put the names in another table and just put name_id instead of repeating the same name several times.
The other schema is to have patient table and a table for each value that contains patient_id and value and the table name is the name for that value
We have an Online Judge (something similar to SPOJ.pl) where we conduct these 3 hour long contests during the weekends, by the end of which we have close to around 1000 submissions. And we store all these runs on a single table (which includes the submitted code). The present structure of the table is as follows :
+------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+----------+------+-----+---------+----------------+
| rid | int(11) | NO | PRI | NULL | auto_increment |
| pid | int(11) | YES | | NULL | |
| tid | int(11) | YES | | NULL | |
| language | tinytext | YES | | NULL | |
| name | tinytext | YES | | NULL | |
| code | longtext | YES | | NULL | |
| time | tinytext | YES | | NULL | |
| result | tinytext | YES | | NULL | |
| error | text | YES | | NULL | |
| access | tinytext | YES | | NULL | |
| submittime | int(11) | YES | | NULL | |
| output | longtext | YES | | NULL | |
+------------+----------+------+-----+---------+----------------+
Now the problem is that, every time we use the ORDER BY clause while querying within this, it ends up sorting the whole table. And in case of more than 1000 rows, each with a considerable amount of data, the time taken is significant. Please note that this is after OPTIMIZE-ing the tables at regular intervals say there have been changes made to the submissions. We do have two options :
Split up the tables after say around 100 entries.
Store the huge chunks of data (the submitted code) as files instead of inserting them as values into the table to reduce the overhead.
Is there another alternative/workaround to this were we can actually maintain the table structure as it is? I could really use some help here. Thanks.
My recommendation would be to do something called vertical partitioning: split the table into multiple tables, with different columns.
In this case, I would have one table that has all the small data: rid, pid, tid, language, name, time, result, access, submittime.
A second table would have: rid, code, error, output.
This way, you can do the sort on the first table and then join in the other fields after the sort. I put code, error, and output together since they sort of seem to go together.
I am experimenting with mysql partitioning ( splitting the table up to help it scale better ), and I am having a problem with the keys on the table. First, I am using a python's threaded comments module... here is the schema
+-----------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+------------------+------+-----+---------+-------+
| content_type_id | int(11) | NO | MUL | NULL | |
| object_id | int(10) unsigned | NO | | NULL | |
| parent_id | int(11) | YES | MUL | NULL | |
| user_id | int(11) | NO | MUL | NULL | |
| date_submitted | datetime | NO | | NULL | |
| date_modified | datetime | NO | | NULL | |
| date_approved | datetime | YES | | NULL | |
| comment | longtext | NO | | NULL | |
| markup | int(11) | YES | | NULL | |
| is_public | tinyint(1) | NO | | NULL | |
| is_approved | tinyint(1) | NO | | NULL | |
| ip_address | char(15) | YES | | NULL | |
| id | int(11) | YES | | NULL | |
+-----------------+------------------+------+-----+---------+-------+
Note, I have modified this database by dropping the id col (primary by default), and re adding it.
Essentially, I want to have id AND content_type_id as my primary keys. I also want id to auto increment. Is this possible.
Second question. Since I am just learning about mysql partitioning, I am wondering if my partitioning logic is sound. There are 67 different content_types, and some (maybe all) of those content types allow comments to be made on them. My plan is to partition based on the type of object that is being commented on. For instance, the images will be commented on a lot, so I put any content type pertaining to images into one partition, and another content type that can be commented on is "blog entries", so there is a separate partition for that, and so on and so on. This will allow me to spread these partitions possibly to dedicated machines as the load grows. How is my understanding of this concept so far?
Thanks so much!
Since id will be auto incremented, it can be the primary key all by itself. Adding content_type to the primary key would not gain you anything in regards to the uniqueness of the key.
If you want to add an index for faster performance to the 2 columns, then add an alternate unique index to the table with the 2 columns instead of trying to add them both to the primary key. However, be aware that enforing uniqueness on the 2 columns would be a waste since id is already guaranteed to be unique by itself, so a regular index would make more sense if needed.
When the staff change the information of product name, option name or prices. It should insert the data into history log and who done it.
items table:
item_id (PK)
item_name
item_description
Note: item prices are in the item_options table
item_options table:
option_id (PK)
item_id (FK)
option_name
option_price
A item can have 1 or more options.
If I want to change the name items.item_name, It should copy the current record to the history table, delete current record from items table and then insert a new record with the new information in the items table?
What about the item_options, how would that work? If there are multiple options from specific item_id, do that mean I need to duplicate options to history table?
What Audit logging/history tables should look like for items and item_options?
Thanks
Your audit data should be stored per-table, rather than all in one place. What you'd do is create an audit table for each of the tables you want to track, and create triggers to create a record in the audit table for any data-manipulation operation on the audited table.
It's definitely advisable to disallow DELETE operations on the items and item_options tables - add flags like item_active and item_option_active so that you can softdelete them instead. This is normal practice in situations where you're doing things like storing invoices that reference products ordered in the past, and need the data for historical reporting purposes, but not for day-to-day use.
Your audit tables aren't something you should use for referencing old data, your normal data model should support simply "hiding" old data where it's likely that it's still going to be used, and storing multiple versions of data that will change over time.
For auditing, it's also useful to store the username of the last user to modify a given record - when used from a web application, you can't use MySQL's USER() function to get any useful information about who's logged on. Adding a column and populating it means you can use that information in your audit triggers.
NB: I'll assume that you won't allow item IDs to be changed under normal conditions - that would make your auditing system more complex.
If you add active flags, and last-modified-by data to your tables, they'll look something like:
Items table:
mysql> desc items;
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| item_id | int(11) | NO | PRI | NULL | auto_increment |
| item_name | varchar(100) | YES | | NULL | |
| item_description | text | YES | | NULL | |
| item_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
Item options table:
mysql> desc item_options;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| option_id | int(11) | NO | PRI | NULL | auto_increment |
| item_id | int(11) | YES | MUL | NULL | |
| option_name | varchar(100) | YES | | NULL | |
| option_price | int(11) | YES | | NULL | |
| option_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
Your audit tables need to store four extra pieces of information:
Audit ID - this ID is only unique for the history of this table, it's not a global value
Change made by - the database user who made the change
Change date/time
Action type - INSERT or UPDATE (or DELETE if you were allowing it)
Your audit tables should look something like:
Items audit table:
mysql> desc items_audit;
+------------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+--------------+------+-----+---------+----------------+
| audit_id | int(11) | NO | PRI | NULL | auto_increment |
| item_id | int(11) | YES | | NULL | |
| item_name | varchar(100) | YES | | NULL | |
| item_description | text | YES | | NULL | |
| item_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
| change_by | varchar(50) | YES | | NULL | |
| change_date | datetime | YES | | NULL | |
| action | varchar(10) | YES | | NULL | |
+------------------+--------------+------+-----+---------+----------------+
Item options audit table:
mysql> desc item_options_audit;
+---------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-----+---------+----------------+
| audit_id | int(11) | NO | PRI | NULL | auto_increment |
| option_id | int(11) | YES | | NULL | |
| item_id | int(11) | YES | | NULL | |
| option_name | varchar(100) | YES | | NULL | |
| option_price | int(11) | YES | | NULL | |
| option_active | tinyint(4) | YES | | NULL | |
| modified_by | varchar(50) | YES | | NULL | |
| change_by | varchar(50) | YES | | NULL | |
| change_date | datetime | YES | | NULL | |
| action | varchar(10) | YES | | NULL | |
+---------------+--------------+------+-----+---------+----------------+
Don't use foreign keys on your audit tables; the rows in the audit tables aren't child rows of the records they're auditing, so foreign keys aren't of any use.
Triggers
NB: MySQL doesn't support multi-statement-type triggers, so you need one for each of INSERT, UPDATE and DELETE (if applicable).
Your triggers simply need to INSERT all the NEW values into the audit table. The trigger definitions for the items table might be:
/* Trigger for INSERT statements on the items table */
CREATE DEFINER=`root`#`localhost` TRIGGER trigger_items_insert_audit
AFTER INSERT ON items
FOR EACH ROW BEGIN
INSERT INTO items_audit (
item_id, item_name, item_description,
item_active, modified_by, change_by,
change_date, action
) VALUES (
NEW.item_id, NEW.item_name, NEW.item_description,
NEW.item_active, NEW.modified_by, USER(),
NOW(), 'INSERT'
);
END;
/* Trigger for UPDATE statements on the items table */
CREATE DEFINER=`root`#`localhost` TRIGGER trigger_items_update_audit
AFTER UPDATE ON items
FOR EACH ROW BEGIN
INSERT INTO items_audit (
item_id, item_name, item_description,
item_active, modified_by, change_by,
change_date, action
) VALUES (
NEW.item_id, NEW.item_name, NEW.item_description,
NEW.item_active, NEW.modified_by, USER(),
NOW(), 'UPDATE'
);
END;
Create similar triggers for the item_options table.
Update: Data History In E-commerce
The auditing we did above will allow you to keep a history of any given database table, but creates a data store that isn't suitable for use for data that needs to be accessed regularly.
In an e-commerce system, keeping usable historical data is important, so that you can change attributes while still presenting old values in certain situations.
This should be completely separate from your auditing solution
The best way to store history is to create a history table for each attribute that needs to be stored historically. This Stackoverflow question has some good information about keeping a history of a given attribute.
In your situation, if you're only concerned about price and title, you'd create a prices table, and an item_titles table. Each one would have a foreign key to either the item_options table or the items table (the master tables would still store the current price, or title), and would have the price or title, with its effective dates. These tables should have fine-grained (possibly column-based) permissions to avoid updating the effective_from dates, and the actual values once the record is inserted.
You should use the auditing solution above on these tables also.
if you do not have a bunch of constraints - then your data will get messed up in a hurry when you orphan the item entries by removing option entries and visaversa.
what you are asking for can be done in triggers, but this is not probably what you want.
imaging if you have an item with 2 options.
now you change the item name, that item gets deelted (and moved to history) - you have unlinkable options... is that what you intend?
what about order or other things that reference the items? same issues.
instead, create trigger logic to only allow 'reasonable' edits to the item. if desired, put a copy of the record into a parallel history table, but DO NOT delete the original.
you may also consider adding a status column to the item or some date ranges in order to account for the idea that this item is currently available or whatever other status you may need.