Database table design for handle 'stock' details MySQL - mysql

Is for a small shop of Maximum 10 items.
As per current design, handling quantity in prod_master table itself as shown below.
My confusion is, need to create another table to handle the query 'Whenever new stocks added'. May I know the standard way to design this ?
MariaDB [niffdb]> desc prod_master;
+--------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------+------+-----+---------+----------------+
| prod_id | int(4) | NO | PRI | NULL | auto_increment |
| prod_desc | varchar(50) | NO | | NULL | |
| qty_in_stock | int(6) unsigned | NO | | 0 | |
+--------------+-----------------+------+-----+---------+----------------+
3 rows in set (0.003 sec)
Planning to make another table stock_history with fields prod_id, date_added and qty in relation with prod_master. But my doubt is , it is the standard way of doing ?

Create a new table purchases with columns
id INT AUTO_INCREMENT PRIMARY KEY
purchase_date DATETIME
prod_id INT
quantity INT
Whenever you purchase something enter a new row in this table and update the quantity in the prod_master table as well.

For your purpose need two table , can name product_masters and product_transactions
In product_transactions you can add all the purchases with quantity and purchase date time. product master will always updated with latest stock ,average cost or latest purchased cost whatever you want.
by this design you can quickly access the new stock see all the purchases made on products

Related

MySQL - insert rows in one table and then update another with the auto increment ID

I have 2 tables called applications and filters. The structure of the tables are as follows:
mysql> DESCRIBE applications;
+-----------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+---------------------+------+-----+---------+----------------+
| id | tinyint(3) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| filter_id | int(3) | NO | | NULL | |
+-----------+---------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
mysql> DESCRIBE filters;
+----------+----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------------------+------+-----+---------+----------------+
| id | smallint(5) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| label | varchar(255) | NO | | NULL | |
| link | varchar(255) | NO | | NULL | |
| anchor | varchar(100) | NO | | NULL | |
| group_id | tinyint(3) unsigned | NO | MUL | NULL | |
| comment | varchar(255) | NO | | NULL | |
+----------+----------------------+------+-----+---------+----------------+
7 rows in set (0.02 sec)
What I want to do is select all the records in applications and make a corresponding record in filters (so that filters.name is the same as applications.name). When the record is inserted in filters I want to get the primary key (filters.id) of the newly inserted record - which is an auto increment field - and update applications.filter_id with it. I should clarify that applications.filter_id is a field I've created for this purpose and contains no data at the moment.
I am a PHP developer and have written a script which can do this, but want to know if it's possible with a pure MySQL solution. In pseudo-code the way my script works is as follows:
Select all the records in applications
Do a foreach loop on (1)
Insert a record in filters (filters.name == applications.name)
Store the inserted ID (filters.id) to a variable and then update applications.filter_id with the variable's data.
I'm unaware of how to do the looping (2) and storing the auto increment ID (4) in MySQL.
I have read about Get the new record primary key ID from mysql insert query? so am aware of LAST_INSERT_ID() but not sure how to reference this in some kind of "loop" which goes through each of the applications records.
Please can someone advise if this is possible?
I don't think this is possible to do this with only one request to mysql.
But, i think this is a good use case for mysql triggers.
I think you should write it like this :
CREATE TRIGGER after_insert_create_application_filter AFTER INSERT
ON applications FOR EACH ROW
BEGIN
INSERT INTO filters (name) VALUES (NEW.name);
UPDATE applications SET filter_id = LAST_INSERT_ID() WHERE id = NEW.id;
END
This trigger is not tested but you should understand the way to write it.
If you don't know mysql triggers, you can read this part of the documentation.
This isn't an answer to your question, more a comment on your database design.
First of all, if the name field needs to contain the same information, they should be the same type and size (varchar(255))
Overall though, I think the schema you're using for your tables is wrong. Your description says that each record in applications can only hold one filter_id. If that is the case, there's no point in using two separate tables.
If there is a chance that there will be a many-to-one relationship, link the records via the relevant primary key. If multiple records in application can relate to a single filter, store filters.id in the applications table. If there are multiple filters for a single application, store applications.id in the filters table.
If there is a many-to-many relationship, create another table to store it:
CREATE TABLE `application_filters_mappings` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`application_id` int(10) unsigned NOT NULL,
`filters_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
);

Insert with on duplicate key update ignores index

So I've got a table product_supplier that I need to add data to from import_tbl. Product_supplier has three columns product_id, supplier_id and price. Import_tbl has the same columns plus some extra. What's most important and what I can't get working is that when a specific combination of product_id and supplier_id exists, only the price should be updated. If that combination does not exist a new row needs to be added. I tried this query
INSERT INTO product_supplier (product_id, supplier_id, price)
SELECT i.product_id, i.supplier_id, i.price
FROM import_tbl i
ON DUPLICATE KEY UPDATE
price = i.price
This one works if I add a row with a new product_id, but it totally ignores the supplier_id. So it won't add new rows if I a row uses the same product_id but a different supplier_id.
I think this has something to do with indexes, and I tried unique indexes for both product_id, and supplier_id and a multiple-column index of both product_id and supplier_id. But when I put EXPLAIN in front of the query it never recognises any indexes. Please some help, thanks!
Table structure of product_supplier
+---------------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------------------+---------+------+-----+---------+----------------+
| product_supplier_id | int(11) | NO | PRI | NULL | auto_increment |
| product_id | int(11) | NO | UNI | 0 | |
| supplier_id | int(11) | NO | MUL | 0 | |
| price | int(11) | NO | | 0 | |
+---------------------+---------+------+-----+---------+----------------+
It looks like you have a key problem.
The "ON DUPLICATE KEY UPDATE" pays attention to the table's primary key only, in this case a combo primary of product_supplier_id plus product_id. The product_supplier_id field isn't being included in your INSERT, and is then being auto-generated.
If you really want to make this commit as a single action (instead of check for existing then choose to either insert or update) then you'll need to move the primary key to be based on a combo of product_id and supplier_id and drop the auto-increment field.
If you need to be able to have more than one price per product/supplier then you can't use ON DUPLICATE KEY UPDATE and will need to run multiple queries.

MySQL: Count items by categories

I've created a table that holds items according to categories:
+------------+---------------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+---------------------+------+-----+-------------------+----------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| name | varchar(30) | YES | | NULL | |
| category | varchar(30) | YES | MUL | NULL | |
| timestamp | timestamp | NO | | CURRENT_TIMESTAMP | |
| data | mediumblob | YES | | NULL | |
+------------+---------------------+------+-----+-------------------+----------------+
Old data is deleted using a sliding window technique, meaning that only the last N items in each category are kept in the table.
How can I keep track the total number of the items per category, and the timestamp of the first item in the category?
Edit - COUNT and MIN on the original table won't work, because this is a Sliding Window data structure meaning that the first items have already been deleted.
Clearly you need to keep a separate table when you delete the records. Your table should summarize the categories and include the fields:
Category first start time
Total number of items in the category
and so on.
When you go to delete, you need to update this table. In general, I prefer to use stored procedures to handle database maintenance, so this code could be added to the stored procedure. Others prefer triggers, so you could have a delete trigger that does the same thing.
try with SELECT count(id) FROM table GROUP BY category

Break this Query into batches

I have a MySQL table contacts, with structure as follows
+--------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| contactee_id | int(11) | NO | MUL | 0 | |
| contacter_id | int(11) | NO | MUL | 0 | |
+--------------+----------+------+-----+---------+----------------+
contactee_id and contacter_id are both ids, which together defines a relationship between two users. In order to calculate the count of relations, a user have, I have the following query
INSERT INTO followers (id, followers)
SELECT contactee_id, 1
FROM contacts
ON DUPLICATE KEY
UPDATE followers = followers + 1
The problem with this query is that it locks the contacts table for too long (more than 16 minutes). I want to get it done in batches, so that the SQL does not locks contacts table for too long. Few ways, I thought of, but they all need to lock the entire table. Is there a way this could be done?
If you just want the count of relations use the count and group by together like
SELECT contactee_id,count(contacter_id) FROM contacts group by contactee_id;
This will give you all the contactee_id and the number of contacter_id's for each contactee
Run query for some records and then save the id of the last record in a table or filesystem, start next query from that id and update it every cycle.

History price list for invoices?

When the customer place an order, the item_id and option_id are stored in the order_items table, from there it will generate invoice for the customer. However the price of the item always change every few months and it will affect old invoices information.
What are the solution to fix this problem? I do not want to store the price and item name in the order_items table.
I have read the possible solution is to create history_prices table (audit system via trigger or SQL insert query manually via php?), is Audit best solution or is there any other solution?
Can you provide example how do I create history_prices table, so when I change the price from item_options.option_price - it will be stored into history_prices table?
Right now I have over 200,000 rows in item_options table, do I need to copy the prices into history_prices?
I need an efficient way so the invoices will not be affected from the new price change.
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 | |
+---------------+--------------+------+-----+---------+----------------+
order_items table:
mysql> desc order_items;
+----------------+---------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------+------+-----+---------+----------------+
| order_items_id | int(11) | NO | PRI | NULL | auto_increment |
| order_id | int(11) | NO | | NULL | |
| item_id | int(11) | NO | | NULL | |
| option_id | int(11) | NO | | NULL | |
+----------------+---------+------+-----+---------+----------------+
Check the following designs out:
Design 1: Stores a rolling history of changes to the item (New row if anything changes: name, description, price).
Design 2: New row on Price change only.
Alternatively, you can store the price with the order itself.
This is a matter of opinion, some will agree that a historical price lookup will be ok, my opinion is that it is not.
The problem with looking up a history of prices and determining the invoice price from that is there is plenty of room for error. You will have several pieces of logic used to determine the right price, all of which are prone to errors. You could forget to convert the time zone of the invoice, and this could cause it to be on the wrong side of a price change. You could forget to make any applied discounts or coupon codes date sensitive, etc. What about ever changing shipping charges?
It is best to store the actual invoice price with the invoice itself. Disk space is cheap, use the redundancy to sleep better at night.
The best thing you can do is creating a a column in order_items for the price. And that's also the most straightforward.
If you want to create a table with price history for reporting use, that might be fine. But do not give yourself the painful headache of querying the price history just to get some items' price. The price IS an attribute of the item. The price might change due to promotion, discount, special offer, etc.