MySQL - Requête UPDATE basée sur SELECT Query

501

Je dois vérifier (à partir du même tableau) s'il y a une association entre deux événements basés sur la date et l'heure.

Un ensemble de données contiendra la date-heure de fin de certains événements et l'autre ensemble de données contiendra la date-heure de début pour d'autres événements.

Si le premier événement se termine avant le deuxième événement, je voudrais les relier.

Ce que j'ai jusqu'à présent, c'est:

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

Puis je les rejoins:

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

Puis-je ensuite, en fonction de mon champ validation_check, exécuter une requête UPDATE avec le SELECT imbriqué?

John M
la source
2
Je ne suis pas sûr de ce que vous demandez? Essayez-vous de comprendre comment effectuer une mise à jour avec un SQL Select?
RiddlerDev

Réponses:

812

Vous pouvez en fait le faire de deux manières:

Syntaxe de jointure de mise à jour 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

Syntaxe SQL ANSI:

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)

Choisissez celui qui vous semble le plus naturel.

Eric
la source
92
Le premier formulaire (mise à jour avec jointure) sera beaucoup plus efficace que le second. Le premier ferait une jointure unique, tandis que le second exécuterait la requête de sélection pour chaque ligne de tableA.
ColinM
16
Pour le premier exemple, ne devez-vous pas utiliser une jointure interne? La jointure gauche n'entraînera-t-elle pas la validation de validation_check sur null pour les enregistrements tableA sans un enregistrement tableB correspondant?
Cerin
3
@Cerin oui qui m'est arrivé. Cela devrait être une jointure intérieure! Ou laissez-le simplement comme rejoindre. Si vous n'avez pas de jointure interne, la jointure gauche signifie que tous les enregistrements tableA seront mis à jour! C'est très dangereux!
CMCDragonkai
10
Merci pour le premier (y). Alors que cette réponse a plus de 7 ans. Je ne peux pas croire pourquoi personne n'a déclaré que la seconde ne fonctionne pas dans certaines bases de données telles que MySQL. Vous obtiendrez cette erreur:You can't specify target table ___ for update in FROM clause SQL.sql
Jugali Lakota
1
Notez également que jusqu'à récemment, la première approche ne fonctionnait pas avec MySQL lorsque tableA= tableB. Vous êtes obligé de créer une table temporaire pour stocker le résultat intermédiaire. (a dû écrire une requête similaire pour un script de migration)
svvac
301
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

J'espère que cela fonctionne pour toi.

massquote
la source
5
C'est de loin la requête la plus rapide. Edit: Ayant dest avec 22K lignes, et src avec 4K lignes, il a fallu moins de 1 seconde pour terminer, tandis que la réponse du haut plus de 60 secondes.
Chris Dev
1
Oui, c'est la requête la plus rapide, BTW vous pouvez également ajouter la clause WHERE
robinmag
1
le plus rapide n'implique pas toujours bien, cette mise à jour ne fonctionnera pas dans tous les cas, en fait, dans certains cas, vous aurez un comportement inattendu, tout cela pourquoi ne pas mettre une condition et ce n'est pas une jointure
Emiliano
114

Facile dans MySQL:

UPDATE users AS U1, users AS U2 
SET U1.name_one = U2.name_colX
WHERE U2.user_id = U1.user_id
Sergio
la source
58

Si quelqu'un cherche à mettre à jour des données d'une base de données à une autre, quelle que soit la table qu'il cible, il doit y avoir des critères pour le faire.

Celui-ci est meilleur et propre pour tous les niveaux:

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! Ça marche super!

Avec la compréhension ci-dessus, vous pouvez modifier les champs définis et les critères "on" pour faire votre travail. Vous pouvez également effectuer les vérifications, puis extraire les données dans les tables temporaires, puis exécuter la mise à jour à l'aide de la syntaxe ci-dessus en remplaçant les noms de table et de colonne.

J'espère que cela fonctionne, sinon faites le moi savoir. Je vais vous écrire une requête exacte.

KMX
la source
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 ;

J'espère que cela vous aidera dans le cas où vous devez faire correspondre et mettre à jour entre deux tables.

Don
la source
12

J'ai trouvé cette question en recherchant ma propre solution à une jointure très complexe. Il s'agit d'une solution alternative, à une version plus complexe du problème, que je pensais être utile.

Je devais remplir le champ product_id dans la table des activités, où les activités sont numérotées dans une unité, et les unités sont numérotées dans un niveau (identifié à l'aide d'une chaîne ?? N), de sorte que l'on puisse identifier les activités à l'aide d'une SKU, c'est-à-dire L1U1A1. Ces références sont ensuite stockées dans une table différente.

J'ai identifié les éléments suivants pour obtenir une liste de 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)

J'ai trouvé que c'était trop complexe pour être incorporé dans un SELECT dans mysql, alors j'ai créé une table temporaire, et je l'ai jointe à l'instruction de mise à jour: -

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;

J'espère que quelqu'un trouve cela utile

sibaz
la source
deux requêtes peuvent ne pas donner un résultat cohérent dans un environnement multithread.
donald
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];
bhavik
la source
4

Vous pouvez mettre à jour les valeurs d'une autre table à l'aide d'une jointure interne comme celle-ci

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

Suivez ici pour savoir comment utiliser cette requête http://www.voidtricks.com/mysql-inner-join-update/

ou vous pouvez utiliser select as subquery pour ce faire

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

requête expliquée en détails ici http://www.voidtricks.com/mysql-update-from-select/

Anand Roshan
la source
4

Vous pouvez utiliser:

UPDATE Station AS st1, StationOld AS st2
   SET st1.already_used = 1
 WHERE st1.code = st2.code
SergeyUr
la source
3

Pour la même 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;
Gnanam pragasam
la source
1

J'ai eu un problème avec les entrées en double dans une table elle-même. Ci-dessous, les approches fonctionnaient pour moi. Il a également été préconisé par @sibaz.

Enfin, je l'ai résolu en utilisant les requêtes ci-dessous:

  1. La requête de sélection est enregistrée dans une table temporaire

    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. La table temporaire est jointe à la requête de mise à jour.

    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
    )

Je ne suis pas très expérimenté avec SQL, veuillez conseiller une meilleure approche que vous connaissez.

Les requêtes ci-dessus concernent le serveur MySql.

Meule
la source