MySQL - UPDATE-Abfrage basierend auf SELECT-Abfrage

501

Ich muss (aus derselben Tabelle) überprüfen, ob es eine Zuordnung zwischen zwei Ereignissen basierend auf Datum und Uhrzeit gibt.

Ein Datensatz enthält das Enddatum und die Endzeit bestimmter Ereignisse, und der andere Datensatz enthält das Startdatum und die Startzeit für andere Ereignisse.

Wenn das erste Ereignis vor dem zweiten Ereignis abgeschlossen ist, möchte ich sie verknüpfen.

Was ich bisher habe ist:

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

Dann schließe ich mich ihnen an:

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

Kann ich dann basierend auf meinem Feld validation_check eine UPDATE-Abfrage mit dem verschachtelten SELECT ausführen?

John M.
quelle
2
Ich bin nicht sicher, was Sie fragen? Versuchen Sie herauszufinden, wie Sie ein Update mit einer SQL-Auswahl durchführen können?
RiddlerDev

Antworten:

811

Sie können dies auf zwei Arten tun:

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)

Wählen Sie das aus, was Ihnen am natürlichsten erscheint.

Eric
quelle
92
Das erste Formular (Update mit Join) wird viel effizienter sein als das zweite. Der erste würde einen einzelnen Join ausführen, während der zweite die Auswahlabfrage für jede Zeile von tableA ausführen würde.
ColinM
16
Sollten Sie für das erste Beispiel keinen inneren Join verwenden? Wird der linke Join nicht dazu führen, dass validation_check für tableA-Datensätze ohne entsprechenden tableB-Datensatz auf null gesetzt wird?
Cerin
3
@Cerin ja das ist mir passiert. Es sollte innere Verbindung sein! Oder lassen Sie es einfach als Beitritt. Wenn Sie keinen inneren Join haben, bedeutet der linke Join, dass alle tableA-Datensätze aktualisiert werden! Das ist sehr gefährlich!
CMCDragonkai
10
Danke für das erste (y). Während diese Antwort mehr als 7 Jahre alt ist. Ich kann nicht glauben, warum niemand angegeben hat, dass die zweite in einer Datenbank wie MySQL nicht funktioniert. Sie erhalten diesen Fehler:You can't specify target table ___ for update in FROM clause SQL.sql
Jugali Lakota
1
Beachten Sie außerdem, dass der erste Ansatz bis vor kurzem mit MySQL nicht funktionierte, wenn tableA= tableB. Sie müssen eine temporäre Tabelle erstellen, um das Zwischenergebnis zu speichern. (musste eine ähnliche Abfrage für ein Migrationsskript schreiben)
svvac
301
UPDATE
    `table1` AS `dest`,
    (
        SELECT
            *
        FROM
            `table2`
        WHERE
            `id` = x
    ) AS `src`
SET
    `dest`.`col1` = `src`.`col1`
WHERE
    `dest`.`id` = x
;

Hoffe das funktioniert bei dir.

massquote
quelle
5
Dies ist bei weitem die schnellste Abfrage. Bearbeiten: Nachdem dest mit 22K-Zeilen und src mit 4K-Zeilen ausgeführt wurde, dauerte der Vorgang weniger als 1 Sekunde, während die oberste Antwort über 60 Sekunden dauerte.
Chris Dev
1
Ja, dies ist die schnellste Abfrage. Übrigens können Sie auch die WHERE-Klausel hinzufügen
robinmag
1
schnellste nicht immer implizieren gut, dieses Update wird nicht in allen Fällen funktionieren, in der Tat werden Sie in einigen Fällen ein unerwartetes Verhalten haben, all dies ist, warum nicht eine Bedingung setzen und das ist kein Join
Emiliano
114

Einfach in MySQL:

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

Wenn jemand versucht, Daten von einer Datenbank in eine andere zu aktualisieren, unabhängig davon, auf welche Tabelle er abzielt, muss es einige Kriterien dafür geben.

Dieser ist besser und sauber für alle Ebenen:

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! Es funktioniert super!

Mit dem obigen Verständnis können Sie die festgelegten Felder und "Ein" -Kriterien ändern, um Ihre Arbeit zu erledigen. Sie können auch die Überprüfungen durchführen, dann die Daten in die temporäre (n) Tabelle (n) ziehen und dann die Aktualisierung mit der obigen Syntax ausführen, wobei Ihre Tabellen- und Spaltennamen ersetzt werden.

Hoffe es funktioniert, wenn nicht, lass es mich wissen. Ich werde eine genaue Anfrage für Sie schreiben.

KMX
quelle
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 ;

Ich hoffe, dies hilft Ihnen in einem Fall, in dem Sie zwischen zwei Tabellen übereinstimmen und diese aktualisieren müssen.

Don
quelle
12

Ich fand diese Frage, als ich nach meiner eigenen Lösung für einen sehr komplexen Join suchte. Dies ist eine alternative Lösung für eine komplexere Version des Problems, die ich für nützlich hielt.

Ich musste das Feld product_id in der Aktivitätstabelle ausfüllen, in der Aktivitäten in einer Einheit und Einheiten in einer Ebene nummeriert sind (identifiziert durch eine Zeichenfolge ?? N), so dass man Aktivitäten mit einer SKU, dh L1U1A1, identifizieren kann. Diese SKUs werden dann in einer anderen Tabelle gespeichert.

Ich habe Folgendes identifiziert, um eine Liste von activity_id vs product_id zu erhalten: -

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)

Ich fand, dass dies zu komplex war, um es in ein SELECT in MySQL zu integrieren, also erstellte ich eine temporäre Tabelle und verband diese mit der Update-Anweisung: -

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;

Ich hoffe, jemand findet das nützlich

Sibaz
quelle
Zwei Abfragen liefern in einer Umgebung mit mehreren Threads möglicherweise kein konsistentes Ergebnis.
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
quelle
4

Sie können Werte aus einer anderen Tabelle mithilfe dieser inneren Verknüpfung aktualisieren

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

Folgen Sie hier, um zu erfahren, wie diese Abfrage verwendet wird: http://www.voidtricks.com/mysql-inner-join-update/

oder Sie können dazu select als Unterabfrage verwenden

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

Abfrage hier ausführlich erklärt http://www.voidtricks.com/mysql-update-from-select/

Anand Roshan
quelle
4

Sie können verwenden:

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

Für dieselbe Tabelle,

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
quelle
1

Ich hatte ein Problem mit doppelten Einträgen in einer Tabelle. Nachfolgend finden Sie die Ansätze, die für mich funktioniert haben. Es wurde auch von @sibaz befürwortet.

Schließlich habe ich es mit den folgenden Fragen gelöst:

  1. Die Auswahlabfrage wird in einer temporären Tabelle gespeichert

    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. Die temporäre Tabelle wird in der Aktualisierungsabfrage verknüpft.

    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
    )

Ich habe keine großen Erfahrungen mit SQL. Bitte empfehlen Sie einen besseren Ansatz, den Sie kennen.

Die obigen Abfragen beziehen sich auf den MySQL-Server.

Rick
quelle