MERGE¶
Inserts, updates, and deletes values in a table that are based on values in a second table or a subquery. Merging can be useful if the second table is a change log that contains new rows (to be inserted), modified rows (to be updated), or marked rows (to be deleted) in the target table.
La commande prend en charge une sémantique pour traiter les cas suivants :
Valeurs qui correspondent (pour les mises à jour et les suppressions).
Values that don’t match (for inserts).
Syntaxe¶
MERGE INTO <target_table>
USING <source>
ON <join_expr>
{ matchedClause | notMatchedClause } [ ... ]
Où :
matchedClause ::= WHEN MATCHED [ AND <case_predicate> ] THEN { UPDATE { ALL BY NAME | SET <col_name> = <expr> [ , <col_name> = <expr> ... ] } | DELETE } [ ... ]notMatchedClause ::= WHEN NOT MATCHED [ AND <case_predicate> ] THEN INSERT { ALL BY NAME | [ ( <col_name> [ , ... ] ) ] VALUES ( <expr> [ , ... ] ) }
Paramètres¶
target_tableSpécifie la table à fusionner.
sourceSpécifie la table ou la sous-requête à joindre à la table cible.
join_exprSpécifie l’expression sur laquelle joindre la table cible et la source.
matchedClause (pour les mises à jour ou les suppressions)¶
WHEN MATCHED ... AND case_predicateSpécifie éventuellement une expression qui, lorsqu’elle est « true », provoque l’exécution de la casse correspondante.
Par défaut : aucune valeur (la casse correspondante est toujours exécutée)
WHEN MATCHED ... THEN { UPDATE { ALL BY NAME | SET ... } | DELETE }Spécifie l’action à effectuer lorsque les valeurs correspondent.
ALL BY NAMEMet à jour toutes les colonnes de la table cible avec les valeurs de la source. Chaque colonne de la table cible est mise à jour avec les valeurs de la colonne portant le même nom à partir de la source.
La table cible et la source doivent avoir le même nombre de colonnes et les mêmes noms pour toutes les colonnes. Toutefois, l’ordre des colonnes peut être différent entre la table cible et la source.
SET col_name = expr [ , col_name = expr ... ]Updates the specified column in the target table by using the corresponding expression for the new column value (can refer to both the target and source relations).
In a single
SETsubclause, you can specify multiple columns to update.DELETESupprime les lignes de la table cible lorsqu’elles correspondent à la source.
notMatchedClause (pour les insertions)¶
WHEN NOT MATCHED ... AND case_predicateSpécifie éventuellement une expression qui, lorsqu’elle est « true », provoque l’exécution de la casse qui ne correspond pas.
Par défaut : aucune valeur (la casse non correspondante est toujours exécutée)
WHEN NOT MATCHED ... THEN INSERT.{ ALL BY NAME | [ ( col_name [ , ... ] ) ] VALUES ( expr [ , ... ] ) }Specifies the action to perform when the values don’t match.
ALL BY NAMEinsère toutes les colonnes de la table cible avec les valeurs de la source. Chaque colonne de la table cible est insérée avec les valeurs de la colonne portant le même nom dans la source.
La table cible et la source doivent avoir le même nombre de colonnes et les mêmes noms pour toutes les colonnes. Toutefois, l’ordre des colonnes peut être différent entre la table cible et la source.
( col_name [ , ... ] )Optionally specifies one or more columns in the target table to be inserted with values from the source.
Default: No value (all columns in the target table are inserted)
VALUES ( expr [ , ... ] )Spécifie les expressions correspondantes pour les valeurs de colonne insérées (doivent se référer aux relations sources).
Notes sur l’utilisation¶
A single MERGE statement can include multiple matching and not-matching clauses (that is,
WHEN MATCHED ...andWHEN NOT MATCHED ...).Any matching or not-matching clause that omits the
ANDsubclause (default behavior) must be the last of its clause type in the statement (for example, aWHEN MATCHED ...clause can’t be followed by aWHEN MATCHED AND ...clause). Doing so results in an unreachable case, which returns an error.
Dupliquer le comportement de jointure¶
Lorsque plusieurs lignes de la table source correspondent à une seule ligne de la table cible, les résultats peuvent être déterministes ou non déterministes. Cette section décrit le comportement MERGE pour ces cas d’utilisation.
Résultats non déterministes pour UPDATE et DELETE¶
When a merge joins a row in the target table against multiple rows in the source, the following join conditions produce nondeterministic results (that is, the system is unable to determine the source value to use to update or delete the target row):
A target row is selected to be updated with multiple values (for example,
WHEN MATCHED ... THEN UPDATE).A target row is selected to be both updated and deleted (for example,
WHEN MATCHED ... THEN UPDATE,WHEN MATCHED ... THEN DELETE).
Dans cette situation, le résultat de la fusion dépend de la valeur spécifiée pour le paramètre de session ERROR_ON_NONDETERMINISTIC_MERGE :
Si TRUE (valeur par défaut), la fusion renvoie une erreur.
Si FALSE, une ligne parmi les doublons est sélectionnée pour effectuer la mise à jour ou la suppression ; la ligne sélectionnée n’est pas définie.
Résultats déterministes pour UPDATE et DELETE¶
Deterministic merges always complete without error. A merge is deterministic if it meets at least one of the following conditions for each target row:
Une ou plusieurs lignes satisfont les clauses
WHEN MATCHED ... THEN DELETEet aucune autre ligne source ne satisfait les clausesWHEN MATCHEDUne seule ligne source satisfait une clause
WHEN MATCHED ... THEN UPDATEet aucune autre ligne source ne satisfait les clausesWHEN MATCHED.
Cela rend MERGE sémantiquement équivalent aux commandes UPDATE et DELETE.
Note
To avoid errors when multiple rows in the data source (that is, the source table or subquery) match the target table based on the ON condition, use GROUP BY in the source clause to ensure that each target row joins against one row (at most) in the source.
In the following example, assume src includes multiple rows with the same k value. It’s ambiguous which values (v) will
be used to update rows in the target row with the same value of k. By using the MAX function and GROUP BY, the query clarifies exactly
which value of v from src is used:
MERGE INTO target
USING (SELECT k, MAX(v) AS v FROM src GROUP BY k) AS b
ON target.k = b.k
WHEN MATCHED THEN UPDATE SET target.v = b.v
WHEN NOT MATCHED THEN INSERT (k, v) VALUES (b.k, b.v);
Résultats déterministes pour INSERT¶
Les fusions déterministes sont toujours complètes et sans erreur.
If the MERGE statement contains a WHEN NOT MATCHED ... THEN INSERT clause, and if there are no matching rows in the target, and if the
source contains duplicate values, then the target gets one copy of the row for each copy in the source. For an example,
see Effectuer une fusion avec des doublons de sources.
Exemples¶
Les exemples suivants utilisent la commande MERGE.
Perform a basic merge that updates values¶
L’exemple suivant effectue une fusion de base qui met à jour les valeurs de la table cible en utilisant des valeurs de la table source. Créez et chargez deux tables :
CREATE OR REPLACE TABLE merge_example_target (id INTEGER, description VARCHAR);
INSERT INTO merge_example_target (id, description) VALUES
(10, 'To be updated (this is the old value)');
CREATE OR REPLACE TABLE merge_example_source (id INTEGER, description VARCHAR);
INSERT INTO merge_example_source (id, description) VALUES
(10, 'To be updated (this is the new value)');
Display the values in the tables:
SELECT * FROM merge_example_target;
+----+---------------------------------------+
| ID | DESCRIPTION |
|----+---------------------------------------|
| 10 | To be updated (this is the old value) |
+----+---------------------------------------+
SELECT * FROM merge_example_source;
+----+---------------------------------------+
| ID | DESCRIPTION |
|----+---------------------------------------|
| 10 | To be updated (this is the new value) |
+----+---------------------------------------+
Run the MERGE statement:
MERGE INTO merge_example_target
USING merge_example_source
ON merge_example_target.id = merge_example_source.id
WHEN MATCHED THEN
UPDATE SET merge_example_target.description = merge_example_source.description;
+------------------------+
| number of rows updated |
|------------------------|
| 1 |
+------------------------+
Display the new values in the target table (the source table is unchanged):
SELECT * FROM merge_example_target;
+----+---------------------------------------+
| ID | DESCRIPTION |
|----+---------------------------------------|
| 10 | To be updated (this is the new value) |
+----+---------------------------------------+
SELECT * FROM merge_example_source;
+----+---------------------------------------+
| ID | DESCRIPTION |
|----+---------------------------------------|
| 10 | To be updated (this is the new value) |
+----+---------------------------------------+
Perform a basic merge with multiple operations¶
Perform a basic merge with a mix of operations (INSERT, UPDATE, and DELETE).
Create and load two tables:
CREATE OR REPLACE TABLE merge_example_mult_target (
id INTEGER,
val INTEGER,
status VARCHAR);
INSERT INTO merge_example_mult_target (id, val, status) VALUES
(1, 10, 'Production'),
(2, 20, 'Alpha'),
(3, 30, 'Production');
CREATE OR REPLACE TABLE merge_example_mult_source (
id INTEGER,
marked VARCHAR,
isnewstatus INTEGER,
newval INTEGER,
newstatus VARCHAR);
INSERT INTO merge_example_mult_source (id, marked, isnewstatus, newval, newstatus) VALUES
(1, 'Y', 0, 10, 'Production'),
(2, 'N', 1, 50, 'Beta'),
(3, 'N', 0, 60, 'Deprecated'),
(4, 'N', 0, 40, 'Production');
Display the values in the tables:
SELECT * FROM merge_example_mult_target;
+----+-----+------------+
| ID | VAL | STATUS |
|----+-----+------------|
| 1 | 10 | Production |
| 2 | 20 | Alpha |
| 3 | 30 | Production |
+----+-----+------------+
SELECT * FROM merge_example_mult_source;
+----+--------+-------------+--------+------------+
| ID | MARKED | ISNEWSTATUS | NEWVAL | NEWSTATUS |
|----+--------+-------------+--------+------------|
| 1 | Y | 0 | 10 | Production |
| 2 | N | 1 | 50 | Beta |
| 3 | N | 0 | 60 | Deprecated |
| 4 | N | 0 | 40 | Production |
+----+--------+-------------+--------+------------+
L’exemple de fusion suivant effectue les actions suivantes sur la table merge_example_mult_target :
Supprime la ligne contenant
iddéfini sur1parce que la colonnemarkedpour la ligne avec le mêmeidestYdansmerge_example_mult_source.Met à jour les valeurs
valetstatusde la ligne oùidest défini sur2avec les valeurs dans la ligne avec le mêmeiddansmerge_example_mult_source, carisnewstatusest défini sur1pour la même ligne dansmerge_example_mult_source.Met à jour la valeur
valde la ligne oùidest défini sur3avec la valeur de la ligne avec le mêmeiddansmerge_example_mult_source. L’instruction MERGE ne met pas à jour la valeurstatusdansmerge_example_mult_targetcarisnewstatusest défini sur0pour cette ligne dansmerge_example_mult_source.Insère la ligne où
idest défini sur4car la ligne existe dansmerge_example_mult_sourceet il n’y a pas de ligne correspondante dansmerge_example_mult_target.
MERGE INTO merge_example_mult_target
USING merge_example_mult_source
ON merge_example_mult_target.id = merge_example_mult_source.id
WHEN MATCHED AND merge_example_mult_source.marked = 'Y'
THEN DELETE
WHEN MATCHED AND merge_example_mult_source.isnewstatus = 1
THEN UPDATE SET val = merge_example_mult_source.newval, status = merge_example_mult_source.newstatus
WHEN MATCHED
THEN UPDATE SET val = merge_example_mult_source.newval
WHEN NOT MATCHED
THEN INSERT (id, val, status) VALUES (
merge_example_mult_source.id,
merge_example_mult_source.newval,
merge_example_mult_source.newstatus);
+-------------------------+------------------------+------------------------+
| number of rows inserted | number of rows updated | number of rows deleted |
|-------------------------+------------------------+------------------------|
| 1 | 2 | 1 |
+-------------------------+------------------------+------------------------+
Pour voir les résultats de la fusion, affichez les valeurs dans la table merge_example_mult_target :
SELECT * FROM merge_example_mult_target ORDER BY id;
+----+-----+------------+
| ID | VAL | STATUS |
|----+-----+------------|
| 2 | 50 | Beta |
| 3 | 60 | Production |
| 4 | 40 | Production |
+----+-----+------------+
Effectuer une fusion à l’aide de ALL BY NAME¶
L’exemple suivant effectue une fusion qui insère et met à jour des valeurs dans la table cible en utilisant des valeurs de la table source. L’exemple utilise les sous-clauses WHEN MATCHED ... THEN ALL BY NAME et WHEN NOT MATCHED ... THEN ALL BY NAME pour spécifier que la fusion s’applique à toutes les colonnes.
Créez deux tables avec le même nombre de colonnes et les mêmes noms pour les colonnes, mais avec un ordre différent pour deux des colonnes :
CREATE OR REPLACE TABLE merge_example_target_all (
id INTEGER,
x INTEGER,
y VARCHAR);
CREATE OR REPLACE TABLE merge_example_source_all (
id INTEGER,
y VARCHAR,
x INTEGER);
Load the tables:
INSERT INTO merge_example_target_all (id, x, y) VALUES
(1, 10, 'Skiing'),
(2, 20, 'Snowboarding');
INSERT INTO merge_example_source_all (id, y, x) VALUES
(1, 'Skiing', 10),
(2, 'Snowboarding', 25),
(3, 'Skating', 30);
Display the values in the tables:
SELECT * FROM merge_example_target_all;
+----+----+--------------+
| ID | X | Y |
|----+----+--------------|
| 1 | 10 | Skiing |
| 2 | 20 | Snowboarding |
+----+----+--------------+
SELECT * FROM merge_example_source_all;
+----+--------------+----+
| ID | Y | X |
|----+--------------+----|
| 1 | Skiing | 10 |
| 2 | Snowboarding | 25 |
| 3 | Skating | 30 |
+----+--------------+----+
Run the MERGE statement:
MERGE INTO merge_example_target_all
USING merge_example_source_all
ON merge_example_target_all.id = merge_example_source_all.id
WHEN MATCHED THEN
UPDATE ALL BY NAME
WHEN NOT MATCHED THEN
INSERT ALL BY NAME;
+-------------------------+------------------------+
| number of rows inserted | number of rows updated |
|-------------------------+------------------------|
| 1 | 2 |
+-------------------------+------------------------+
Display the new values in the target table:
SELECT *
FROM merge_example_target_all
ORDER BY id;
+----+----+--------------+
| ID | X | Y |
|----+----+--------------|
| 1 | 10 | Skiing |
| 2 | 25 | Snowboarding |
| 3 | 30 | Skating |
+----+----+--------------+
Effectuer une fusion avec des doublons de sources¶
Perform a merge in which the source has duplicate values and the target has no matching values. All copies of the source record are inserted into the target. For more information, see Résultats déterministes pour INSERT.
Truncate both tables and load new rows into the source table that include duplicates:
TRUNCATE table merge_example_target;
TRUNCATE table merge_example_source;
INSERT INTO merge_example_source (id, description) VALUES
(50, 'This is a duplicate in the source and has no match in target'),
(50, 'This is a duplicate in the source and has no match in target');
La merge_example_target n’a aucune valeur. Affichez les valeurs dans la table merge_example_source :
SELECT * FROM merge_example_source;
+----+--------------------------------------------------------------+
| ID | DESCRIPTION |
|----+--------------------------------------------------------------|
| 50 | This is a duplicate in the source and has no match in target |
| 50 | This is a duplicate in the source and has no match in target |
+----+--------------------------------------------------------------+
Run the MERGE statement:
MERGE INTO merge_example_target
USING merge_example_source
ON merge_example_target.id = merge_example_source.id
WHEN MATCHED THEN
UPDATE SET merge_example_target.description = merge_example_source.description
WHEN NOT MATCHED THEN
INSERT (id, description) VALUES
(merge_example_source.id, merge_example_source.description);
+-------------------------+------------------------+
| number of rows inserted | number of rows updated |
|-------------------------+------------------------|
| 2 | 0 |
+-------------------------+------------------------+
Display the new values in the target table:
SELECT * FROM merge_example_target;
+----+--------------------------------------------------------------+
| ID | DESCRIPTION |
|----+--------------------------------------------------------------|
| 50 | This is a duplicate in the source and has no match in target |
| 50 | This is a duplicate in the source and has no match in target |
+----+--------------------------------------------------------------+
Perform a merge with deterministic and nondeterministic results¶
Merge records by using joins that produce nondeterministic and deterministic results.
Create and load two tables:
CREATE OR REPLACE TABLE merge_example_target_orig (k NUMBER, v NUMBER);
INSERT INTO merge_example_target_orig VALUES (0, 10);
CREATE OR REPLACE TABLE merge_example_src (k NUMBER, v NUMBER);
INSERT INTO merge_example_src VALUES (0, 11), (0, 12), (0, 13);
Lorsque vous effectuez la fusion dans l’exemple suivant, plusieurs mises à jour entrent en conflit les unes avec les autres. Si le paramètre de session ERROR_ON_NONDETERMINISTIC_MERGE est défini sur true, l’instruction MERGE renvoie une erreur. Sinon, l’instruction MERGE met à jour merge_example_target_clone.v avec une valeur (par exemple, 11, 12 ou 13) de l’une des lignes en double (ligne non définie) :
CREATE OR REPLACE TABLE merge_example_target_clone
CLONE merge_example_target_orig;
MERGE INTO merge_example_target_clone
USING merge_example_src
ON merge_example_target_clone.k = merge_example_src.k
WHEN MATCHED THEN UPDATE SET merge_example_target_clone.v = merge_example_src.v;
Les mises à jour et les suppressions sont en conflit les unes avec les autres. Si le paramètre de session ERROR_ON_NONDETERMINISTIC_MERGE est défini sur true, l’instruction MERGE renvoie une erreur. Sinon, l’instruction MERGE supprime la ligne ou met à jour merge_example_target_clone.v avec une valeur (par exemple, 12 ou 13) de l’une des lignes en double (ligne non définie) :
CREATE OR REPLACE TABLE merge_example_target_clone
CLONE merge_example_target_orig;
MERGE INTO merge_example_target_clone
USING merge_example_src
ON merge_example_target_clone.k = merge_example_src.k
WHEN MATCHED AND merge_example_src.v = 11 THEN DELETE
WHEN MATCHED THEN UPDATE SET merge_example_target_clone.v = merge_example_src.v;
Les suppressions multiples ne sont pas en conflit les unes avec les autres. Les valeurs jointes qui ne correspondent à aucune clause n’empêchent pas la suppression (merge_example_src.v = 13). L’instruction MERGE réussit et la ligne cible est supprimée :
CREATE OR REPLACE TABLE target CLONE merge_example_target_orig;
MERGE INTO merge_example_target_clone
USING merge_example_src
ON merge_example_target_clone.k = merge_example_src.k
WHEN MATCHED AND merge_example_src.v <= 12 THEN DELETE;
Les valeurs jointes qui ne correspondent à aucune clause n’empêchent pas une mise à jour (merge_example_src.v = 12, 13). L’instruction MERGE réussit et la ligne cible est définie sur target.v = 11 :
CREATE OR REPLACE TABLE merge_example_target_clone CLONE target_orig;
MERGE INTO merge_example_target_clone
USING merge_example_src
ON merge_example_target_clone.k = merge_example_src.k
WHEN MATCHED AND merge_example_src.v = 11
THEN UPDATE SET merge_example_target_clone.v = merge_example_src.v;
Utilisez GROUP BY dans la clause source pour vous assurer que chaque ligne cible se joint à une ligne dans la source :
CREATE OR REPLACE TABLE merge_example_target_clone CLONE merge_example_target_orig;
MERGE INTO merge_example_target_clone
USING (SELECT k, MAX(v) AS v FROM merge_example_src GROUP BY k) AS b
ON merge_example_target_clone.k = b.k
WHEN MATCHED THEN UPDATE SET merge_example_target_clone.v = b.v
WHEN NOT MATCHED THEN INSERT (k, v) VALUES (b.k, b.v);
Effectuer une fusion basée sur les valeurs DATE¶
Dans l’exemple suivant, la table members enregistre les noms, adresses et frais actuels (members.fee) versés à une salle de sport locale. La table signup enregistre la date d’inscription de chaque membre (signup.date). L’instruction MERGE applique des frais standard de 40 $ aux membres qui se sont inscrits à la salle il y a plus de 30 jours, après l’expiration de l’essai gratuit :
MERGE INTO members m
USING (SELECT id, date
FROM signup
WHERE DATEDIFF(day, CURRENT_DATE(), signup.date::DATE) < -30) s
ON m.id = s.id
WHEN MATCHED THEN UPDATE SET m.fee = 40;