I have two tables in MySQL and I would like to update a column in one of them to match values from another.
The tables each have a customer and part number column.
Table 1:
Customer_Name | Part_Number | Demand | Allocation
Table 2:
Customer_Name | Part_Number | Demand
I want to update table 1 to add table 2 demand to the allocation figure in table 1, if the part number and customer both exist in table 2.
A query I have attempted so far:
UPDATE `Packing_Dispatch` SET Allocation = `Packing_Allocation`.Demand WHERE
Customer_Name = `Packing_Allocation`.Customer_Name AND Part_Number = `Packing_Allocation`.Part_Number
How can I do this?
You can try below
UPDATE `Packing_Dispatch`
Join `Packing_Allocation`
SET Allocation = `Packing_Allocation`.Demand
WHERE Customer_Name = `Packing_Allocation`.Customer_Name AND Part_Number = `Packing_Allocation`.Part_Number
Related
I am using Server version: 5.5.28-log MySQL Community Server (GPL).
I have a big table consist of 279703655 records called table A. I have to perform join on this table with one of my changelog table B and then insert matching records in new tmp table C.
B table has index on column type.
A table consist of prod_id,his_id and other columns.A table has index on both column prod_id,history_id.
When i am going to perform the following query
INSERT INTO C(prod,his_id,comm)
SELECT DISTINCT a.product_id,a.history_id,comm
FROM B as b INNER JOIN A as a ON a.his_id = b.his_id AND b.type="applications"
GROUP BY prod_id
ON DUPLICATE KEY UPDATE
`his_id` = VALUES(`his_id`);
it takes 7 to 8 min to insert records.
Even if i perform simple count from table A it took 15 min to give me count.
I have also tried a procedure to insert records in Limit but due to count query takes 15 min it is more slower then before.
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE i INT DEFAULT 0;
SELECT COUNT(*) FROM A INTO n;
SET i=5000000;
WHILE i<n DO
INSERT INTO C(product_id,history_id,comments)
SELECT a.product_id,a.history_id,a.comments FROM B as b
INNER JOIN (SELECT * FROM A LIMIT i,1) as a ON a.history_id=b.history_id;
SET i = i + 5000000;
END WHILE;
End
But the above code is also take 15 to 20 min o execute.
Please suggest me how i make it faster.
Below is EXPLAIN result:
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------------+-------------+
| 1 | SIMPLE | a | ALL | (NULL) | (NULL) | (NULL) | (NULL) | 279703655 | |
| 1 | SIMPLE | b | eq_ref | PRIMARY | PRIMARY | 8 | DB.a.history_id | 1 | Using index |
+----+-------------+-------+--------+---------------+---------+---------+-----------------+--------------+-------------+
(from Comment)
CREATE TABLE B (
history_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
history_hash char(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
type enum('products','brands','partnames','mc_partnames','applications') NOT NULL,
stamp timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (history_id),
UNIQUE KEY history_hash (history_hash),
KEY type (type),
KEY stamp (stamp)
);
Let's first look at the tables.
What you call table B is really a history table. Its primary key is the history_id.
What you call table A is really a product table with one product per row and product_id its primary key. Each product also has a history_id. Thus you have created a 1:n relation. A product has one history row; one history row relates to multiple products.
You are selecting the product table rows that have an 'application' type history entry. This should be written as:
select product_id, history_id, comm
from product
where history_id in
(
select history_id
from history
where type = 'applications'
);
(A join would work just as well, but isn't as clear. As there is only one history row per product, you can't get duplicates. Both GROUP BY and DISTINCT are completely superfluous in your query and should be removed in order not to give the DBMS unecessary work to do. But as mentioned: better don't join at all. If you want rows from table A, select from table A. If you want to look up rows in table B, look them up in the WHERE clause, where all criteria belongs.)
Now, we would have to know how many rows may be affected. If only 1% of all history rows are 'applications', then an index should be used. Preferably
create index idx1 on history (type, history_id);
… which finds rows by type and gets their history_id right away.
If, say 20%, of all all history rows are 'applications', then reading the table sequentially might be more efficient.
Then, how many product rows may we get? Even with a single history row, we might get millions of related product rows. Or vice versa, with millions of history rows we might get no product row at all. Again, we can provide an index, which may or may not be used by the DBMS:
create index idx2 on product (history_id, product_id, comm);
This is about as fast as it gets. Two indexes offered and a proper written query without an unnecessary join. There were times when MySQL had performance problems with IN. People rewrote the clause with EXISTS then. I don't think this is still necessary.
As of MySQL 8.0.3, you can create histogram statistics for tables.
analyze history update histogram on type;
analyze product update histogram on history_id;
This is an important step to help the optimizer to find the optimal way to select the data.
Indexes needed (assuming it is history_id, not his_id):
B: INDEX(type, history_id) -- in this order. Note: "covering"
A: INDEX(history_id, product_id, comm)
What column or combination of columns provides the uniqueness constraint that IODKU needs?
Really-- Provide SHOW CREATE TABLE.
I got a big table and I need to modify the structure.
Here is the table structure.
Table Name : "Articles"
+---------+---------------+-------------------+--------------+
| id(int) | details(text) | category(varchar) | tag(varchar) |
+---------+---------------+-------------------+--------------+
Important points:
There are around 250k (250,000) rows in this table
There are around 10k unique categories
What I need to change
I created table called "category" and then make the category column as a foreign key for that table.
This is what I expect:
I need to move category names to category table and then need to update articles table with category ID.
Table Name : "Articles"
+---------+---------------+-------------------+--------------+
| id(int) | details(text) | category(int) | tag(varchar) |
+---------+---------------+-------------------+--------------+
Table Name : "Category"
+---------+-------------------+
| id(int) | category(varchar) |
+---------+-------------------+
Is it possible to do just using MySQL? (I know that how to do that using some PHP scripts and MySQL commands). But I asked it here because if I can do it with just MySQL I can save lot of time.
Assumming that category(id) column is automatically filled (it is auto_increment column):
SET FOREIGN_KEY_CHECKS=0;
INSERT INTO Category( category )
SELECT DISTINCT category(varchar)
FROM Articles;
UPDATE Articles a, Category c
SET a.category(int) = c.id
WHERE a.category(varchar) = c.category
;
SET FOREIGN_KEY_CHECKS=1;
I use category(varchar) and category(int) to distinguish one (int) category column from the other (varchar) category in the same table. This is of course syntactically incorrect, you must use proper and distinct column names instead of category(xxx)
I need to insert some data in a table named ‘queue’ which is a patient queue in a particular date . Two fields data will be inserted .Two fields name are ‘PatientID’ and ‘Visiting Date’. Table ‘queue' like
QueueID | PatientID | Visiting_date |
-------------|-------------------|-------------------------|
1 | 4 | Current date |
table:queue
But while inserting the record there are two conditions :
Condition 1 : patitentID comes from patient table (given below)
Condition 2 : one record will be inserted to ‘queue’ table if it does not exist to prevent repeatation.ie PatientID=4 will not be inserted if already inserted.
-------------|-----------------|------------------|
patitentID | Patient Name | Contact no |
-------------|-----------------|------------------|
4 | David | 01245785874 |
table:patient
My SQL is: (it does not work)
INSERT INTO `queue`(`patientID`, `Visiting_date`)
SELECT patient.`patientID`,’CURDATE()’ FROM `patient`
WHERE NOT EXISTS (
SELECT `patientID`, `visiting_date`FROM `queue`
WHERE `patientID` = '4' AND `visting_date`=CURDATE()
) LIMIT 1;
You could set a foreign key to make sure the patients id exists.
In the Queue table you can set patientID as unique, this makes sure you can insert only unique id's in the queue table.
Also if you would like to be able to insert the same userID but with different dates you could specify unique constraint for multiple columns in MySQL.
If you want to solve it with a mysql query only you can use this question.
I would use a separate query to check if there is a user with that ID in that table.
SELECT * FROM queue WHERE PatientID = 4;
and then check the result of that query, if it returns a row, that means that there is a user in there and you don't do anything.
If the query doesn't return a row, that means you can now use a query to inert a user. Like this
INSERT INTO queue (PatientID, VisitingDate);
I want to create a trigger to decrease the quantity of available items after an order has been made.
I tried to create a trigger. I'm using phpMyAdmin, setting trigger AFTER INSERT in the table products_in_order
SET #qtt = (
SELECT quantity
FROM products_in_order
ORDER BY inorder_id DESC
LIMIT 1)
SET #code = (
SELECT product_code
FROM products_in_order
ORDER BY inorder_id DESC
LIMIT 1)
UPDATE products
SET quantity = quantity-#qtt
WHERE product_code=#code
Why does the first SET work, and the second, too, but as soon as I write them both, i get an error?
How to make this trigger work correctly?
Sample data:
products represents all products available in the shop, and has columns:
product_code | name | price | quantity
product_in_order represents a set of products of the same type, that can be added to order. It has colums:
inorder_id | product_code | price | order_no
inorder_id | product_code | price | quantity | order_no
When somebody adds a set of products to the order, I want the overall quantity of that product to decrease.
You don't need to join back to the newly inserted / updated table* - just use the New pseudo row from within your trigger, which already has the values you need to join into the master Product table:
CREATE TRIGGER `MyTrigger`
AFTER INSERT ON `products_in_order`
FOR EACH ROW
BEGIN
UPDATE products
SET quantity = quantity-New.quantity
WHERE product_code=New.product_code;
END;
SqlFiddle here demonstrating that the starting value of Product is depleted by the amount inserted into products_in_order for the applicable product code.
* Assuming inorder_id is an AUTO_INCREMENT, selecting from this table twice without any locking considerations will also be prone to concurrency issues, e.g. if another writer inserts another row while your trigger is executing. Another good reason to use New
I have two tables with the following layout ...
------------- -------------------------
| Master | | History |
------------- -------------------------
| id | name | | id | name | master_id |
------------- -------------------------
The history table contains rows where the master_id is NULL. Those I copy into the master table.
INSERT master (name)
SELECT name
FROM histories h
WHERE h.master_id = NULL
How can I update the master_id in the history table with the id of the associated object in the master table? This update should happen in the same step as the insertion is made. I use MySQL if this is of interest.
It is possible to insert into master table records with IDs based on some information from the other table.
For example, you can use the histories.id + last master.id:
LOCK TABLES master WRITE, histories AS h WRITE;
SELECT id FROM master ORDER BY id DESC LIMIT 1 INTO #last_master_id;
INSERT INTO master (id, name)
SELECT h.id + #last_master_id, h.name FROM histories h;
UPDATE histories h SET h.master_id = h.id + #last_master_id;
UNLOCK TABLES;
This works as long as you use integer IDs and if you don't mind that the new ID is based on the other one.
If you wanted to use some non-deterministic IDs, such as UUIDs, the solution would require a few more steps:
Add a temporary column to the histories table.
Fill with the new IDs (update histories set tmp_uuid = UUID(), something like that).
Insert into master select tmp_uuid from histories...
Update histories
Drop the temporary column.
One advantage of using UUIDs is that you don't need to lock the tables. You don't need to worry about other session inserting a record and taking your ID, because the other session generates a different ID.
The SQL documentation here: http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html
suggests that you should be able to do something like the following:
INSERT master (name)
SELECT name, id
FROM history h
WHERE h.master_id = NULL
UPDATE History SET master_id = LAST_INSERT_ID()
WHERE History.id = h.id;
Though I'm not 100% on the syntax as I don't have a SQL instance I can run this against.