Insert with on duplicate key update ignores index - mysql

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.

Related

Database table design for handle 'stock' details 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

MySQL Adding Foreign Key Error 1215

I know such a question is asked before. I made sure that they have the same data type and also checked my syntax, but I am still getting the error:
ALTER TABLE meetings ADD FOREIGN KEY (ownerName) REFERENCES employees(name);
ERROR 1215 (HY000): Cannot add foreign key constraint
mysql> desc `meetings`;
+-----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| room | int(6) | NO | | NULL | |
| ownerName | varchar(30) | NO | | NULL | |
| ownerID | varchar(30) | NO | | NULL | |
+-----------+-------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql> desc `employees`;
+----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| name | varchar(30) | NO | | NULL | |
| username | varchar(30) | NO | PRI | NULL | |
| pswd | varchar(255) | YES | | NULL | |
+----------+--------------+------+-----+---------+-------+
What am I doing wrong?
name is not primary key in employees table so .. try using username
ALTER TABLE meetings ADD FOREIGN KEY (ownerName) REFERENCES employees(username);
or as suggested by DanielE or you can use the column name but need an UNIQUE index for this column
Change the primary key of 'employees' from user name to name. Then you can use
ALTER TABLE meetings ADD FOREIGN KEY (ownerName) REFERENCES employees(name);
What am I doing wrong? Error 1215 is probably the least of the problems here.
Some of the answers given for this question suggest making username the referenced column in employees rather than name, which is fine as far as it goes, but ignores some really fundamental issues in the schema and quite possibly wasn't the poster's intention for these columns. The rest of this answer is based on my own set of assumptions.
meetings table
Looking at the meetings table, I'm left wondering about the purpose of the ownerID column. Since the intention is to have ownerName as a foreign key to employees, what exactly is ownerID? The name suggests it also somehow references employees, but there is no id or ownerID in employees. Also, if any column starting owner... refers to an employee then why would you need both in the meetings table? One of them is surely redundant. Why is ownerID a VARCHAR(30)? ID columns tend to be INT. Of course, I may be reading to much into this and ownerID may have some other purpose that has nothing to do with an employee, but if that's the case the name is likely going to cause confusion in the future.
The meetings table also has an INT surrogate key in id. There's another INT for room. Since room isn't a foreign key, it suggests that rooms are either consistently identified only by number (which would be strange in my experience) and that there is nothing more to a 'room' that's worth capturing (e.g. location, capacity, equipment etc.) to bother with modelling data about the room in a separate table (again unlikely). Alternatively, room might itself be a foreign key referencing an INT id column in an, as yet undefined, rooms table.
employees table
If we accept ownerID as a more appropriate foreign key to the employee that owns the meeting (it uses less memory to index than either name or username) then consistency would suggest another surrogate key id as the primary key in the employees table. It's not necessary to do this, username would be unique and is fine on it's own, but it's simpler and more efficient. The other suggestion made that name should be the PK in employees is wrong - it presupposes that names are always unique.
A single column to cover an employee name would also be unusual.
The point made about referencing a PK or a unique index is well made (even if it's not strictly necessary in Innodb), I'd just say that ownerName is the wrong foreign key and username and name are the wrong references because there is a better alternative.
And, finally, is a NULL password (pswd) a good idea?

Partitioning with primary key gives Error ERROR 1503 (HY000)

It may sound similar but,I am working on partitioning on some table...the table looks like
mysql> DESC SHOPS;
+-------------------+-------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+-------------+------+-----+-------------------+-----------------------------+
| SHOP_ID | int(255) | NO | PRI | NULL | |
| SHOP_NAME | varchar(50) | YES | | NULL | |
| SHOP_CREATED_DATE | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------------------+-------------+------+-----+-------------------+-----------------------------+
3 rows in set (0.00 sec)
so i have search feature where people can search only by shop name so table have around 1 million records so i wanted to RANGE partitioning on shop name alphabetically but i cant do since i have primary key shop_id and shop name can be same...and getting error
ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the
table's partitioning function
Solution:
ALTER TABLE SHOPS ADD CONSTRAINT T UNIQUE (SHOP_ID,SHOP_NAME);
And do partitioning ...i cant do this because it does not make sure shop_id is unique(Primary Key)
You can, and you must. Assuming you always let AUTO_INCREMENT do its thing, shop_id will always be unique, and any index starting with shop_id is all you need.
int(255) -- The (255) means nothing. An INT (SIGNED, by default) has a range of -2 billion to +2 billion and occupies 4 bytes, regardless of the (...) after it..
There is probably no performance advantage (or any other advantage) of Partitioning this table. If you think otherwise, please show us a query that you think will benefit.
Please use SHOW CREATE TABLE; it is more descriptive than DESCRIBE.

Get the auto increment-primary key column programatically

witch is the auto increment field in a mysql table?
I have a table structure, for example:
table name is my_table and the fields are my_id, my_name, my_blah.. The one of fields is an auto incremented primary key. Witch is it?
How can I get the name of auto increment field on this table with a php code and/or a mysql query?
You can use the MySQL SHOW COLUMNS query to retrieve information about the columns in a table:
mysql> SHOW COLUMNS FROM `test`;
+----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| col1 | varchar(100) | YES | | NULL | |
| col2 | int(11) | YES | | NULL | |
+----------+--------------+------+-----+---------+----------------+
The extra column will contain auto_increment for the primary key field.
You could try with a
SHOW COLUMNS FROM TableName
See here: http://dev.mysql.com/doc/refman/5.0/en/show-columns.html
Use a MySQL client and issue the query SHOW CREATE TABLE my_table.
It shows you the code one needs to run to create that table. You can see the column names, types (and lengths), other attributes each column may have (they depend on the type). AUTO_INCREMENT is such an attribute.
It also shows you the PK and the indexes of the table.

When to add index on joined tables

I have a mysql table with 9 million records that doesn't have any indices set. I need to join this to another table based on a common ID. I'm going to add an index to this ID, but I also have other fields in the select and where clause.
Should I add an index to all of the fields in the where clause?
What about the fields in the select clause? Should I create one index for all fields, or an index per field?
Update - Added tables and query
Here is the query - I need to get the number of sales, item name, and item ID by item based on the store name and store ID (the store name and ID by themselves are not unique)
SELECT COUNT(*) as salescount, items.itemName, CONCAT(items.ID, items.productcode) as itemId
FROM items JOIN sales ON items.itemId = sales.itemId WHERE items.StoreName = ?
AND sales.storeID = ? GROUP BY items.ItemId ORDER BY salescount DESC LIMIT 10;
Here is the sales table:
+----------------+------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------+------------------------------+------+-----+---------+-------+
| StoreId | bigint(20) unsigned | NO | | NULL | |
| ItemId | bigint(20) unsigned | NO | | NULL | |
+----------------+------------------------------+------+-----+---------+-------+
and the items table:
+--------------------+------------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------------------+------+-----+---------+-------+
| ItemId | bigint(20) unsigned | NO | PRI | NULL | |
| ProductCode | bigint(20) unsigned | NO | | NULL | |
| ItemName | varchar(100) | NO | | NULL | |
| StoreName | varchar(100) | NO | PRI | NULL | |
+--------------------+------------------------------+------+-----+---------+-------+
You should index all fields that will be searched for in the leading table in the WHERE clause and in the driven table in the WHERE and JOIN clauses.
Making the indexes to cover all fields used in the query (including SELECT and ORDER BY clauses) will also help, since no table lookups will be needed.
Just post your query here and I'll probably be able to tell you how to index the tables.
Update:
Your query will return at most 1 row with 1 as a COUNT(*)
This will select the sale with the given StoreID (which is the PRIMARY KEY), and join the items on the sale's itemId and given StoreName (this combination is a PRIMARY KEY too).
This join either succeeds (returning 1 row) or fails (returning no rows).
If it succeeds, the COUNT(*) will be 1.
If it's really what you want, then your table is indexed fine.
However, it seems to me that your table design is a little more complex and you just missed some fields when copying the field definitions.
Update 2:
Create a composite index on sales (storeId, itemId)
Make sure that you PRIMARY KEY on items is defined as (StoreName, ItemId) (in that order).
If the PK is defined as (ItemID, StoreName), the create an index on items (StoreName, ItemID).
Yes, you really should have indexes, but they should be appropriate for all your queries. Without having a good rummage about in your database its difficult to recommend exactly what indexes to configured.
9 milion rows is enough that indexes will make a big difference - but not so big that you can't afford to tinker a bit.
A crude solution would be to create indexes on items(storeid),items(itemid,storename), items(storename,itemid), sales(itemid),sales(storeid),sales(itemid,storeid) and sales(storeid,itemid) then drop the indexes that aren't getting used.
C.
Indexing is great -- when used in the correct form. Remember, indexes must be indexed.
Concentrate your indexes on your primary, shared keys, as well as fields which require heavy and common data comparisons, such as literal fields and date ranges.
Indexes are great when used correctly, but indexes arn't a cure-all problem. Even properly indexed tables can be brought to their knees with a bad query and a flick of the wrist.