ChatGPT解决这个技术问题 Extra ChatGPT

MySQL - UPDATE query based on SELECT Query

I need to check (from the same table) if there is an association between two events based on date-time.

One set of data will contain the ending date-time of certain events and the other set of data will contain the starting date-time for other events.

If the first event completes before the second event then I would like to link them up.

What I have so far is:

SELECT name as name_A, date-time as end_DTS, id as id_A 
FROM tableA WHERE criteria = 1


SELECT name as name_B, date-time as start_DTS, id as id_B 
FROM tableA WHERE criteria = 2

Then I join them:

SELECT name_A, name_B, id_A, id_B, 
if(start_DTS > end_DTS,'VALID','') as validation_check
FROM tableA
LEFT JOIN tableB ON name_A = name_B

Can I then, based on my validation_check field, run a UPDATE query with the SELECT nested?

I am not sure what you are asking? Are you trying to figure out how to do an update with a SQL Select?

V
Valerian Pereira

You can actually do this one of two ways:

MySQL update join syntax:

UPDATE tableA a
INNER JOIN tableB b ON a.name_a = b.name_b
SET validation_check = if(start_dts > end_dts, 'VALID', '')
-- where clause can go here

ANSI SQL syntax:

UPDATE tableA SET validation_check = 
    (SELECT if(start_DTS > end_DTS, 'VALID', '') AS validation_check
        FROM tableA
        INNER JOIN tableB ON name_A = name_B
        WHERE id_A = tableA.id_A)

Pick whichever one seems most natural to you.


The first form (update with join) is going to be a lot more efficient than the second. The first would do a single join, whereas the second would execute the select query for every row of tableA.
For the first example, shouldn't you use an inner join? Won't the left join result in validation_check being set to null for tableA records without a corresponding tableB record?
@Cerin yea that happened to me. It should be inner join! Or just leave it as join. If you don't have inner join, the left join means that all of tableA records will be updated! This is very dangerous!
Thanks for the first (y). While this answer is more than 7 years old. I can't believe why noone has stated that the second doesn't work in some database such as MySQL. You will get this error : You can't specify target table ___ for update in FROM clause SQL.sql
Also, note that until recently, the first approach didn't work with MySQL when tableA = tableB. You're forced to create a temporary table to store the intermediate result. (had to write a similar query for a migration script)
a
automatix
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

Hope this works for you.


This is by far the fastest query. Edit: Having dest with 22K rows, and src with 4K rows, it took under 1 sec to complete, while the top answer over 60 sec.
Yes, this is the fastest query, BTW you can add WHERE clause too
fastest not always imply good, this update wont work in all cases, in fact some cases you will have a unexpected behavior, all this is why not put a condition and that is not a join
In the latest MySQL versions you need to add an optimizer hint /*+ NO_MERGE(src) * on the query. See dev.mysql.com/doc/refman/8.0/en/update.html (scroll down to where they do CREATE TABLE items.
L
Lucky

Easy in MySQL:

UPDATE users AS U1, users AS U2 
SET U1.name_one = U2.name_colX
WHERE U2.user_id = U1.user_id

best answer for a simple update of one col from another table
This type of implicit join worked better for me than an explicit join using 'INNER JOIN'. In MySQLWorkBench, both updates on a table of 50K records timed out. Using command-line MySQL, 'INNER JOIN' timed out, but the implicit join (above) succeeded, after 11 minutes!
V
Valerian Pereira

If somebody is seeking to update data from one database to another no matter which table they are targeting, there must be some criteria to do it.

This one is better and clean for all levels:

UPDATE dbname1.content targetTable

LEFT JOIN dbname2.someothertable sourceTable ON
    targetTable.compare_field= sourceTable.compare_field
SET
    targetTable.col1  = sourceTable.cola,
    targetTable.col2 = sourceTable.colb, 
    targetTable.col3 = sourceTable.colc, 
    targetTable.col4 = sourceTable.cold 

Traaa! It works great!

With the above understanding, you can modify the set fields and "on" criteria to do your work. You can also perform the checks, then pull the data into the temp table(s) and then run the update using the above syntax replacing your table and column names.

Hope it works, if not let me know. I will write an exact query for you.


good idea! It worked perfect. Thanks
Love this structure, very clear.
S
SergeyYu
UPDATE 
  receipt_invoices dest,
  (
    SELECT 
      `receipt_id`,
      CAST((net * 100) / 112 AS DECIMAL (11, 2)) witoutvat 
    FROM
      receipt 
    WHERE CAST((net * 100) / 112 AS DECIMAL (11, 2)) != total 
      AND vat_percentage = 12
  ) src 
SET
  dest.price = src.witoutvat,
  dest.amount = src.witoutvat 
WHERE col_tobefixed = 1 
  AND dest.`receipt_id` = src.receipt_id ;

Hope this will help you in a case where you have to match and update between two tables.


s
sibaz

I found this question in looking for my own solution to a very complex join. This is an alternative solution, to a more complex version of the problem, which I thought might be useful.

I needed to populate the product_id field in the activities table, where activities are numbered in a unit, and units are numbered in a level (identified using a string ??N), such that one can identify activities using an SKU ie L1U1A1. Those SKUs are then stored in a different table.

I identified the following to get a list of activity_id vs product_id:-

SELECT a.activity_id, w.product_id 
  FROM activities a 
  JOIN units USING(unit_id) 
  JOIN product_types USING(product_type_id) 
  JOIN web_products w 
    ON sku=CONCAT('L',SUBSTR(product_type_code,3), 'U',unit_index, 'A',activity_index)

I found that that was too complex to incorporate into a SELECT within mysql, so I created a temporary table, and joined that with the update statement:-

CREATE TEMPORARY TABLE activity_product_ids AS (<the above select statement>);

UPDATE activities a
  JOIN activity_product_ids b
    ON a.activity_id=b.activity_id 
  SET a.product_id=b.product_id;

I hope someone finds this useful


two query may not give consistent result in multi threaded environment.
b
bhavik
UPDATE [table_name] AS T1,
      (SELECT [column_name] 
        FROM [table_name] 
        WHERE [column_name] = [value]) AS T2 
  SET T1.[column_name]=T2.[column_name] + 1
WHERE T1.[column_name] = [value];

A
Anand Roshan

You can update values from another table using inner join like this

UPDATE [table1_name] AS t1 INNER JOIN [table2_name] AS t2 ON t1.column1_name] = t2.[column1_name] SET t1.[column2_name] = t2.column2_name];

Follow here to know how to use this query http://www.voidtricks.com/mysql-inner-join-update/

or you can use select as subquery to do this

UPDATE [table_name] SET [column_name] = (SELECT [column_name] FROM [table_name] WHERE [column_name] = [value]) WHERE [column_name] = [value];

query explained in details here http://www.voidtricks.com/mysql-update-from-select/


S
SergeyYu

You can use:

UPDATE Station AS st1, StationOld AS st2
   SET st1.already_used = 1
 WHERE st1.code = st2.code

T
Thomas David Baker

For same table,

UPDATE PHA_BILL_SEGMENT AS PHA,
     (SELECT BILL_ID, COUNT(REGISTRATION_NUMBER) AS REG 
       FROM PHA_BILL_SEGMENT
        GROUP BY REGISTRATION_NUMBER, BILL_DATE, BILL_AMOUNT
        HAVING REG > 1) T
    SET PHA.BILL_DATE = PHA.BILL_DATE + 2
 WHERE PHA.BILL_ID = T.BILL_ID;

R
Rick

I had an issue with duplicate entries in one table itself. Below is the approaches were working for me. It has also been advocated by @sibaz.

Finally I solved it using the below queries:

The select query is saved in a temp table IF OBJECT_ID(N'tempdb..#New_format_donor_temp', N'U') IS NOT NULL DROP TABLE #New_format_donor_temp; select * into #New_format_donor_temp from DONOR_EMPLOYMENTS where DONOR_ID IN ( 1, 2 ) -- Test New_format_donor_temp -- SELECT * -- FROM #New_format_donor_temp; The temp table is joined in the update query. UPDATE de SET STATUS_CD=de_new.STATUS_CD, STATUS_REASON_CD=de_new.STATUS_REASON_CD, TYPE_CD=de_new.TYPE_CD FROM DONOR_EMPLOYMENTS AS de INNER JOIN #New_format_donor_temp AS de_new ON de_new.EMP_NO = de.EMP_NO WHERE de.DONOR_ID IN ( 3, 4 )

I not very experienced with SQL please advise any better approach you know.

Above queries are for MySql server.


E
Eliud Amukambwa

if you are updating from a complex query. The best thing is create temporary table from the query, then use the temporary table to update as one query.

    DROP TABLE IF EXISTS cash_sales_sums;
CREATE TEMPORARY TABLE cash_sales_sums as
SELECT tbl_cash_sales_documents.batch_key, COUNT(DISTINCT tbl_cash_sales_documents.cash_sale_number) no_of_docs,
  SUM(tbl_cash_sales_documents.paid_amount) paid_amount, SUM(A.amount - tbl_cash_sales_documents.bonus_amount - tbl_cash_sales_documents.discount_given) amount,
  SUM(A.recs) no_of_entries FROM 
        tbl_cash_sales_documents
    RIGHT JOIN(
        SELECT
            SUM(
                tbl_cash_sales_transactions.amount
            )amount,
            tbl_cash_sales_transactions.cash_sale_document_id,
            COUNT(transaction_id)recs
        FROM
            tbl_cash_sales_transactions
        GROUP BY
            tbl_cash_sales_transactions.cash_sale_document_id
    )A ON A.cash_sale_document_id = tbl_cash_sales_documents.cash_sale_id
    GROUP BY
        tbl_cash_sales_documents.batch_key
ORDER BY batch_key;





UPDATE tbl_cash_sales_batches SET control_totals = (SELECT amount FROM cash_sales_sums WHERE cash_sales_sums.batch_key = tbl_cash_sales_batches.batch_key LIMIT 1),
expected_number_of_documents = (SELECT no_of_docs FROM cash_sales_sums WHERE cash_sales_sums.batch_key = tbl_cash_sales_batches.batch_key),
computer_number_of_documents = expected_number_of_documents,  computer_total_amount = control_totals
WHERE batch_key IN (SELECT batch_key FROM cash_sales_sums);

MVP - Minimal Viable Product. This thing gives a headache. Seriously.
S
Shawn Hou
INSERT INTO all_table
SELECT Orders.OrderID,
    Orders.CustomerID,
    Orders.Amount,
    Orders.ProductID,
    Orders.Date,
    Customer.CustomerName,
    Customer.Address
FROM Orders
JOIN Customer ON Orders.CustomerID=Customer.CustomerID
WHERE Orders.OrderID not in (SELECT OrderID FROM all_table)

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.