MySQL - запрос ОБНОВЛЕНИЯ, основанный на SELECT Query


501

Мне нужно проверить (из той же таблицы), есть ли связь между двумя событиями на основе даты и времени.

Один набор данных будет содержать дату и время окончания определенных событий, а другой набор данных будет содержать дату и время начала других событий.

Если первое событие завершится до второго события, я бы хотел связать их.

То, что я до сих пор это:

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

Тогда я присоединяюсь к ним:

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

Могу ли я затем, основываясь на моем поле validation_check, выполнить запрос UPDATE с вложенным SELECT?


2
Я не уверен, что вы спрашиваете? Вы пытаетесь выяснить, как сделать обновление с помощью SQL Select?
RiddlerDev

Ответы:


812

Вы можете сделать это одним из двух способов:

Синтаксис соединения обновления MySQL:

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:

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)

Выберите тот, который кажется вам наиболее естественным.


92
Первая форма (обновление с объединением) будет намного более эффективной, чем вторая. Первый будет выполнять одиночное соединение, тогда как второй будет выполнять запрос на выборку для каждой строки таблицы A.
ColinM

16
Для первого примера, вы не должны использовать внутреннее соединение? Не приведет ли левое соединение к тому, что validation_check будет иметь значение null для записей tableA без соответствующей записи tableB?
Cerin

3
@ Да, это случилось со мной. Это должно быть внутреннее соединение! Или просто оставьте это как join. Если у вас нет внутреннего соединения, левое соединение означает, что все записи таблицы А будут обновлены! Это очень опасно!
CMCDragonkai

10
Спасибо за первое (у). Пока этому ответу более 7 лет. Я не могу поверить, почему никто не заявил, что второй не работает в некоторой базе данных, такой как MySQL. Вы получите эту ошибку:You can't specify target table ___ for update in FROM clause SQL.sql
Jugali Lakota

1
Также обратите внимание, что до недавнего времени первый подход не работал с MySQL, когда tableA= tableB. Вы вынуждены создать временную таблицу для хранения промежуточного результата. (должен был написать аналогичный запрос для скрипта миграции)
svvac

301
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

Надеюсь, что это работает для вас.


5
Это самый быстрый запрос. Изменить: Имея dest с 22K строк и SRC с 4K строк, это заняло менее 1 секунды, в то время как верхний ответ более 60 секунд.
Крис Дев

1
Да, это самый быстрый запрос, кстати, вы также можете добавить предложение WHERE
robinmag

1
Самое быстрое не всегда означает хорошее, это обновление не будет работать во всех случаях, на самом деле в некоторых случаях у вас будет непредвиденное поведение, все это - то, почему не ставить условие, и это не объединение
Эмилиано

114

Легко в MySQL:

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

58

Если кто-то пытается обновить данные из одной базы данных в другую, независимо от того, на какую таблицу он ориентируется, для этого должны быть определенные критерии.

Этот лучше и чище для всех уровней:

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! Работает отлично!

С учетом вышеизложенного вы можете изменить установленные поля и критерии включения для выполнения своей работы. Вы также можете выполнить проверки, затем перетащить данные во временную таблицу (таблицы) и затем запустить обновление, используя приведенный выше синтаксис, заменяя имена таблиц и столбцов.

Надеюсь, что это работает, если нет, дайте мне знать. Я напишу точный запрос для вас.


24
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 ;

Надеюсь, что это поможет вам в случае, когда вы должны сопоставить и обновить между двумя таблицами.


12

Я нашел этот вопрос в поиске собственного решения очень сложного соединения. Это альтернативное решение более сложной версии проблемы, которая, на мой взгляд, может оказаться полезной.

Мне нужно было заполнить поле product_id в таблице действий, где действия пронумерованы в единице, а единицы пронумерованы на уровне (идентифицируемом с помощью строки ?? N), чтобы можно было идентифицировать операции с использованием SKU, то есть L1U1A1. Эти SKU затем хранятся в другой таблице.

Я определил следующее, чтобы получить список action_id и 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)

Я обнаружил, что это слишком сложно для включения в SELECT в mysql, поэтому я создал временную таблицу и соединил ее с оператором обновления:

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;

Я надеюсь, что кто-то найдет это полезным


Два запроса могут не дать согласованного результата в многопоточной среде.
Дональд

7
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];

4

Вы можете обновить значения из другой таблицы, используя внутреннее соединение, как это

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];

Следуйте здесь, чтобы узнать, как использовать этот запрос http://www.voidtricks.com/mysql-inner-join-update/

или вы можете использовать select как подзапрос, чтобы сделать это

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

запрос подробно объясняется здесь http://www.voidtricks.com/mysql-update-from-select/


4

Ты можешь использовать:

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

3

Для той же таблицы,

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;

1

У меня была проблема с повторяющимися записями в одной таблице. Ниже подходы работали для меня. Это также было поддержано @sibaz.

Наконец я решил это, используя следующие запросы:

  1. Запрос на выборку сохраняется во временной таблице

    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;
  2. Временная таблица объединяется в запросе на обновление.

    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
    )

Я не очень разбираюсь в SQL, пожалуйста, посоветуйте любой лучший подход, который вы знаете.

Выше запросы для сервера MySql.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.