web-dev-qa-db-fra.com

Copier des lignes d'une table à une autre en ignorant les doublons

J'ai 2 tables (srcTable1 et destTable) qui ont des schémas identiques. J'essaie de copier toutes les lignes de srcTable vers destTable et d'ignorer les doublons. Je pensais pouvoir ajouter une clause WHERE à une sous-requête qui ne me donnerait que les lignes qui ne sont pas des doublons Cependant, cela ne semble pas fonctionner. Je ne reçois aucune ligne insérée ou sélectionnée.

INSERT INTO destTable
SELECT * FROM srcTable
WHERE NOT EXISTS(SELECT * FROM destTable)

Je réalise que je pourrais faire quelque chose comme ça:

INSERT INTO destTable
SELECT * FROM srcTable
WHERE MyKey IN (SELECT MyKey FROM destTable)

Cependant, mes tables ont plusieurs clés et je ne vois pas comment vous pouvez le faire avec plusieurs clés.

Une idée de ce que je fais mal ou avez-vous de meilleures idées?

36
Jeff Stock

Votre problème est que vous avez besoin d'une autre clause where dans la sous-requête qui identifie ce qui fait un doublon:

INSERT INTO destTable
SELECT Field1,Field2,Field3,... 
FROM srcTable
WHERE NOT EXISTS(SELECT * 
                 FROM destTable 
                 WHERE (srcTable.Field1=destTable.Field1 and
                       SrcTable.Field2=DestTable.Field2...etc.)
                 )

Comme l'a noté un autre intervenant, une jointure externe est probablement une approche plus concise. Mon exemple ci-dessus était juste une tentative d'expliquer en utilisant votre requête actuelle pour être plus compréhensible. L'une ou l'autre approche pourrait fonctionner techniquement.

INSERT INTO destTable
SELECT s.field1,s.field2,s.field3,... 
FROM srcTable s 
       LEFT JOIN destTable d ON (d.Key1 = s.Key1 AND d.Key2 = s.Key2 AND...)
WHERE d.Key1 IS NULL

Les deux approches ci-dessus supposent que vous ne souhaitez pas insérer de lignes de la source qui sont peut-être déjà dans la destination. Si vous êtes plutôt préoccupé par la possibilité que la source ait des lignes en double, essayez quelque chose comme ça.

INSERT INTO destTable
SELECT Distinct field1,field2,field3,... 
FROM srcTable  

Une dernière chose. Je vous suggérerais également de répertorier les champs spécifiques de votre instruction insert au lieu d'utiliser SELECT *.

46
JohnFx

Je me rends compte que c'est vieux, mais je suis arrivé ici de Google et après avoir examiné la réponse acceptée, j'ai rédigé ma propre déclaration et cela a fonctionné pour moi, j'espère que quelqu'un la trouvera utile:

    INSERT IGNORE INTO destTable SELECT id, field2,field3... FROM origTable

Edit: Cela fonctionne sur MySQL Je n'ai pas testé sur MSSQL

17
Alberto Garcia

J'espère que cette requête vous aidera

INSERT INTO `dTable` (`field1`, `field2`)
SELECT field1, field2 FROM `sTable` 
WHERE `sTable`.`field1` NOT IN (SELECT `field1` FROM `dTable`)
4
Alam Zaib

Quelque chose comme ça?:

INSERT INTO destTable
SELECT s.* FROM srcTable s
LEFT JOIN destTable d ON d.Key1 = s.Key1 AND d.Key2 = s.Key2 AND...
WHERE d.Key1 IS NULL
4
Daniel Pratt

Avez-vous essayé SELECT DISTINCT?

INSERT INTO destTable
SELECT DISTINCT * FROM srcTable
2
Nick Josevski
insert into tbl2
select field1,field2,... from tbl1
where not exists 
    ( 
        select field1,field2,... 
        from person2
        where (tbl1.field1=tbl2.field1 and
        tbl1.field2=tbl2.field2 and .....)
    )

Avez-vous essayé d’abord de supprimer les doublons dans la sous-requête?

INSERT INTO destTable
SELECT source.* FROM(
    SELECT *
    FROM srcTable
    EXCEPT
    SELECT src.* FROM
    srcTable AS src
    INNER JOIN destTable AS dest 
    /* put in below line the conditions to match repeated registers */
        ON dest.SOME_FANCY_MATCH = src.SOME_FANCY_MATCH AND ... 
) as source

Si les ensembles sont très grands, ce n’est peut-être pas la meilleure solution.

0
len.sanag

La solution qui a fonctionné pour moi avec PHP/PDO.

public function createTrainingDatabase($p_iRecordnr){
// Methode: Create an database envirioment for a student by copying the original
// @parameter: $p_iRecordNumber,    type:integer,   scope:local
// @var: $this->sPdoQuery,          type:string,    scope:member 
// @var: $bSuccess,                 type:boolean,   scope:local
// @var: $aTables,                  type:array,     scope:local
// @var: $iUsernumber,              type:integer,   scope:local
// @var: $sNewDBName,               type:string,    scope:local
// @var: $iIndex,                   type:integer,   scope:local 

// -- Create first the name of the new database --
$aStudentcard = $this->fetchUsercardByRecordnr($p_iRecordnr);
$iUserNumber = $aStudentcard[0][3];
$sNewDBName = $_SESSION['DB_name']."_".$iUserNumber;
// -- Then create the new database  --
$this->sPdoQuery = "CREATE DATABASE `".$sNewDBName."`;";
$this->PdoSqlReturnTrue();
// -- Create an array with the tables you want to be copied --
$aTables = array('1eTablename','2ndTablename','3thTablename');
// -- Populate the database --
for ($iIndex = 0; $iIndex < count($aTables); $iIndex++) 
{
 // -- Create the table --
    $this->sPdoQuery = "CREATE TABLE `".$sNewDBName."`.`".$aTables[$iIndex]."` LIKE `".$_SESSION['DB_name']."`.`".$aTables[$iIndex]."`;";
    $bSuccess = $this->PdoSqlReturnTrue();
    if(!$bSuccess ){echo("Could not create table: ".$aTables[$iIndex]."<BR>");}
    else{echo("Created the table ".$aTables[$iIndex]."<BR>");}
    // -- Fill the table --
    $this->sPdoQuery = "REPLACE `".$sNewDBName."`.`".$aTables[$iIndex]."` SELECT * FROM `".$_SESSION['DB_name']."`.`".$aTables[$iIndex]."`";
    $bSuccess = $this->PdoSqlReturnTrue();
    if(!$bSuccess ){echo("Could not fill table: ".$aTables[$iIndex]."<BR>");}
    else{echo("Filled table ".$aTables[$index]."<BR>");}
}

0
Johan de Klijn

DISTINCT est le mot clé que vous recherchez.

Dans MSSQL, la copie de lignes uniques d'une table à une autre peut se faire comme suit:

SELECT DISTINCT column_name
INTO newTable
FROM srcTable

Le column_name est la colonne à partir de laquelle vous recherchez les valeurs uniques.

Testé et fonctionne.

0
Wadih M.