Insérer dans… valeurs (SELECT… FROM…)

1427

J'essaye INSERT INTOune table utilisant l'entrée d'une autre table. Bien que cela soit entièrement réalisable pour de nombreux moteurs de base de données, je semble toujours avoir du mal à me souvenir de la syntaxe correcte pour le SQLmoteur du jour ( MySQL , Oracle , SQL Server , Informix et DB2 ).

Existe-t-il une syntaxe miracle provenant d'un standard SQL (par exemple, SQL-92 ) qui me permettrait d'insérer les valeurs sans se soucier de la base de données sous-jacente?

Claude Houle
la source
1
cet exemple fonctionne: insérer dans tag_zone select @ tag, zoneid, GETDATE (), @ positiong.STIntersects (polygon) from zone
Uğur Gümüşhan

Réponses:

1612

Essayer:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

Il s'agit d'un SQL ANSI standard et devrait fonctionner sur n'importe quel SGBD

Cela fonctionne certainement pour:

  • Oracle
  • MS SQL Server
  • MySQL
  • Postgres
  • SQLite v3
  • Teradata
  • DB2
  • Sybase
  • Vertica
  • HSQLDB
  • H2
  • AWS RedShift
  • SAP HANA
Claude Houle
la source
948

La réponse de Claude Houle : devrait bien fonctionner, et vous pouvez également avoir plusieurs colonnes et d'autres données:

INSERT INTO table1 ( column1, column2, someInt, someVarChar )
SELECT  table2.column1, table2.column2, 8, 'some string etc.'
FROM    table2
WHERE   table2.ID = 7;

Je n'ai utilisé cette syntaxe qu'avec Access, SQL 2000/2005 / Express, MySQL et PostgreSQL, donc ceux-ci devraient être couverts. Il devrait également fonctionner avec SQLite3.

travis
la source
1
que faire si la condition where a changé en table2.country et renvoie un nombre de lignes supérieur à un? J'ai eu un problème similaire ici: stackoverflow.com/questions/36030370/…
vijayrana
1
Il ne devrait pas y avoir de problème lors de l'insertion de plusieurs lignes.
rinukkusu
est-il nécessaire que nous insérions dans toutes les colonnes du tableau
maheshmnj
1
@maheshmnj non, seules les colonnes qui sont définies sur NOT NULL et aucune valeur par défaut ne doivent être incluses, toutes les autres colonnes seront définies sur leurs valeurs par défaut ou NULL
travis
merci pour l'info
maheshmnj
148

Pour obtenir une seule valeur dans une valeur multi INSERTd'une autre table, j'ai fait ce qui suit dans SQLite3:

INSERT INTO column_1 ( val_1, val_from_other_table ) 
VALUES('val_1', (SELECT  val_2 FROM table_2 WHERE val_2 = something))
kylie.a
la source
4
Juste pour clarification: c'est incorrect pour SQLite3. Selon la documentation , les données source pour le INSERTest soit VALUES une SELECTinstruction, mais pas les deux.
2
Il est vrai que la documentation ne le répertorie pas, mais cela fonctionne. Quoi qu'il en soit, je pense que l'utilisation de l'instruction select au lieu de valeurs la rend plus lisible.
Banjocat
1
Cela fonctionne pour spécifier une valeur à l'intérieur d'une ligne, mais le cas plus général nécessite d'obtenir beaucoup de lignes.
Luchostein
Si val_1 ne change pas entre les lignes, alors la syntaxe suivante pourrait fonctionner dans SQLite3? sélectionnez 'foo', some_column de some_table - fonctionne dans SQLServer 2014
Chris B
La documentation énumère ceci (maintenant?): Cette syntaxe est INSERT INTO ... VALUES ([expr], [expr], ...)et l'un des chemins d'accès [expr]est {{NOT} EXISTS} ([select-stmt])- notez que les paranthèses autour de l'instruction select sont obligatoires ( {}ce qui signifie facultatif)
zapl
64

Les deux réponses que je vois fonctionnent correctement dans Informix en particulier, et sont essentiellement du SQL standard. Autrement dit, la notation:

INSERT INTO target_table[(<column-list>)] SELECT ... FROM ...;

fonctionne très bien avec Informix et, je suppose, tous les SGBD. (Il y a 5 ans ou plus, c'est le genre de chose que MySQL ne supportait pas toujours; il a maintenant un support décent pour ce type de syntaxe SQL standard et, AFAIK, cela fonctionnerait bien sur cette notation.) La liste des colonnes est facultatif mais indique les colonnes cibles dans l'ordre, donc la première colonne du résultat du SELECT ira dans la première colonne listée, etc. En l'absence de la liste des colonnes, la première colonne du résultat du SELECT va dans le première colonne de la table cible.

Ce qui peut être différent entre les systèmes, c'est la notation utilisée pour identifier les tables dans différentes bases de données - la norme n'a rien à dire sur les opérations inter-bases de données (et encore moins inter-SGBD). Avec Informix, vous pouvez utiliser la notation suivante pour identifier une table:

[dbase[@server]:][owner.]table

Autrement dit, vous pouvez spécifier une base de données, en identifiant éventuellement le serveur qui héberge cette base de données s'il ne se trouve pas dans le serveur actuel, suivi d'un propriétaire facultatif, d'un point, et enfin du nom réel de la table. Le standard SQL utilise le terme schéma pour ce que Informix appelle le propriétaire. Ainsi, dans Informix, l'une des notations suivantes pourrait identifier une table:

table
"owner".table
dbase:table
dbase:owner.table
dbase@server:table
dbase@server:owner.table

Le propriétaire en général n'a pas besoin d'être cité; cependant, si vous utilisez des guillemets, vous devez obtenir le nom du propriétaire correctement orthographié - il devient sensible à la casse. C'est:

someone.table
"someone".table
SOMEONE.table

tous identifient le même tableau. Avec Informix, il y a une légère complication avec les bases de données MODE ANSI, où les noms des propriétaires sont généralement convertis en majuscules (informix est l'exception). Autrement dit, dans une base de données MODE ANSI (peu utilisée), vous pouvez écrire:

CREATE TABLE someone.table ( ... )

et le nom du propriétaire dans le catalogue système serait "QUELQU'UN", plutôt que "quelqu'un". Si vous mettez le nom du propriétaire entre guillemets, il agit comme un identificateur délimité. Avec SQL standard, les identifiants délimités peuvent être utilisés à de nombreux endroits. Avec Informix, vous pouvez les utiliser uniquement autour des noms de propriétaires - dans d'autres contextes, Informix traite les chaînes entre guillemets simples et doubles comme des chaînes, plutôt que de séparer les chaînes entre guillemets simples en tant que chaînes et les chaînes entre guillemets doubles en tant qu'identificateurs délimités. (Bien sûr, juste pour être complet, il existe une variable d'environnement, DELIMIDENT, qui peut être définie - sur n'importe quelle valeur, mais Y est la plus sûre - pour indiquer que les guillemets doubles entourent toujours les identificateurs délimités et les guillemets simples entourent toujours les chaînes.)

Notez que MS SQL Server parvient à utiliser des [identificateurs délimités] entre crochets. Cela me semble bizarre et ne fait certainement pas partie du standard SQL.

Jonathan Leffler
la source
40

Pour ajouter quelque chose dans la première réponse, lorsque nous voulons seulement quelques enregistrements d'une autre table (dans cet exemple un seul):

INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4) 
VALUES (value1, value2, 
(SELECT COLUMN_TABLE2 
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);
Weslor
la source
4
Cette approche s'applique uniquement à une sous-requête telle qu'une seule colonne est sélectionnée. Dans le cas d'une sous-requête à plusieurs colonnes, une erreur «la sous-requête ne doit renvoyer qu'une seule colonne» sera déclenchée. Adoptez alors la réponse de @ travis.
snowfox
34

La plupart des bases de données suivent la syntaxe de base,

INSERT INTO TABLE_NAME
SELECT COL1, COL2 ...
FROM TABLE_YOU_NEED_TO_TAKE_FROM
;

Chaque base de données que je l' ai utilisé suivre cette syntaxe à savoir DB2, SQL Server, MY SQL,PostgresQL

Santhosh
la source
34

Au lieu d'une VALUESpartie de la INSERTrequête, utilisez simplement la SELECTrequête comme ci-dessous.

INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2
logan
la source
32

Deux approches pour insérer dans avec sous-requête de sélection.

  1. Avec la sous-requête SELECT renvoyant des résultats avec une ligne .
  2. Avec la sous-requête SELECT renvoyant des résultats avec plusieurs lignes .

1. Approche pour la sous-requête With SELECT renvoyant des résultats avec une ligne .

INSERT INTO <table_name> (<field1>, <field2>, <field3>) 
VALUES ('DUMMY1', (SELECT <field> FROM <table_name> ),'DUMMY2');

Dans ce cas, il suppose que la sous-requête SELECT ne renvoie qu'une seule ligne de résultat en fonction de la condition WHERE ou des fonctions d'agrégation SQL telles que SUM, MAX, AVG etc. Sinon, elle générera une erreur

2. Approche pour la sous-requête With SELECT renvoyant des résultats avec plusieurs lignes .

INSERT INTO <table_name> (<field1>, <field2>, <field3>) 
SELECT 'DUMMY1', <field>, 'DUMMY2' FROM <table_name>;

La deuxième approche fonctionnera pour les deux cas.

Mohammed Safeer
la source
29

Cela peut être fait sans spécifier les colonnes dans le INSERT INTO pièce si vous fournissez des valeurs pour toutes les colonnes de la SELECTpièce.

Disons que table1 a deux colonnes. Cette requête devrait fonctionner:

INSERT INTO table1
SELECT  col1, col2
FROM    table2

Cela NE FONCTIONNERAIT PAS (valeur pour col2 n'est pas spécifiée):

INSERT INTO table1
SELECT  col1
FROM    table2

J'utilise MS SQL Server. Je ne sais pas comment les autres RDMS fonctionnent.

northben
la source
24

Voici un autre exemple utilisant des valeurs avec select:

INSERT INTO table1(desc, id, email) 
SELECT "Hello World", 3, email FROM table2 WHERE ...
Sarvar Nishonboev
la source
Ancienne réponse et toujours utile. Assez simple et évident mais couvre exactement mes besoins. Merci!
Sebastian Kaczmarek
21

Insertion simple lorsque la séquence des colonnes du tableau est connue:

    Insert into Table1
    values(1,2,...)

Colonne mentionnant l'insertion simple:

    Insert into Table1(col2,col4)
    values(1,2)

Insertion en masse lorsque le nombre de colonnes sélectionnées d'une table (# table2) est égal à la table d'insertion (Table1)

    Insert into Table1 {Column sequence}
    Select * -- column sequence should be same.
       from #table2

Insertion en masse lorsque vous souhaitez insérer uniquement dans la colonne souhaitée d'une table (table1):

    Insert into Table1 (Column1,Column2 ....Desired Column from Table1)  
    Select Column1,Column2..desired column from #table2
       from #table2
RameezAli
la source
17

Voici un autre exemple où la source est prise à l'aide de plusieurs tables:

INSERT INTO cesc_pf_stmt_ext_wrk( 
  PF_EMP_CODE    ,
  PF_DEPT_CODE   ,
  PF_SEC_CODE    ,
  PF_PROL_NO     ,
  PF_FM_SEQ      ,
  PF_SEQ_NO      ,
  PF_SEP_TAG     ,
  PF_SOURCE) 
SELECT
  PFl_EMP_CODE    ,
  PFl_DEPT_CODE   ,
  PFl_SEC         ,
  PFl_PROL_NO     ,
  PF_FM_SEQ       ,
  PF_SEQ_NO       ,
  PFl_SEP_TAG     ,
  PF_SOURCE
 FROM cesc_pf_stmt_ext,
      cesc_pfl_emp_master
 WHERE pfl_sep_tag LIKE '0'
   AND pfl_emp_code=pf_emp_code(+);

COMMIT;
SWATI BISWAS
la source
17

Utilisez simplement des parenthèses pour la clause SELECT dans INSERT. Par exemple, comme ceci:

INSERT INTO Table1 (col1, col2, your_desired_value_from_select_clause, col3)
VALUES (
   'col1_value', 
   'col2_value',
   (SELECT col_Table2 FROM Table2 WHERE IdTable2 = 'your_satisfied_value_for_col_Table2_selected'),
   'col3_value'
);
Probablement
la source
Merci @Das Son travail pour moi ....
Raj G
16

Voici comment insérer à partir de plusieurs tables. Cet exemple particulier est où vous avez une table de mappage dans un scénario plusieurs à plusieurs:

insert into StudentCourseMap (StudentId, CourseId) 
SELECT  Student.Id, Course.Id FROM Student, Course 
WHERE Student.Name = 'Paddy Murphy' AND Course.Name = 'Basket weaving for beginners'

(Je me rends compte que la correspondance sur le nom de l'élève peut renvoyer plus d'une valeur, mais vous obtenez l'idée. La correspondance sur autre chose qu'un ID est nécessaire lorsque l'ID est une colonne d'identité et est inconnue.)

Ciaran Bruen
la source
14
INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;

Cela fonctionne sur tous les SGBD

Mat
la source
14

Vous pouvez essayer ceci si vous souhaitez insérer toutes les colonnes à l'aide de la SELECT * INTOtable.

SELECT  *
INTO    Table2
FROM    Table1;
Bharath théorare
la source
13

Je préfère en fait ce qui suit dans SQL Server 2008:

SELECT Table1.Column1, Table1.Column2, Table2.Column1, Table2.Column2, 'Some String' AS SomeString, 8 AS SomeInt
INTO Table3
FROM Table1 INNER JOIN Table2 ON Table1.Column1 = Table2.Column3

Il élimine l'étape d'ajout de l'ensemble Insert () et vous sélectionnez simplement les valeurs qui vont dans le tableau.

Grungondola
la source
13

Cela a fonctionné pour moi:

insert into table1 select * from table2

La phrase est un peu différente de celle d'Oracle.

elijah7
la source
12

Pour Microsoft SQL Server, je recommanderai d'apprendre à interpréter le SYNTAX fourni sur MSDN. Avec Google, il est plus facile que jamais de rechercher la syntaxe.

Pour ce cas particulier, essayez

Google: insérer le site: microsoft.com

Le premier résultat sera http://msdn.microsoft.com/en-us/library/ms174335.aspx

faites défiler jusqu'à l'exemple ("Utilisation des options SELECT et EXECUTE pour insérer des données d'autres tables") si vous avez du mal à interpréter la syntaxe donnée en haut de la page.

[ WITH <common_table_expression> [ ,...n ] ]
INSERT 
{
        [ TOP ( expression ) [ PERCENT ] ] 
        [ INTO ] 
        { <object> | rowset_function_limited 
          [ WITH ( <Table_Hint_Limited> [ ...n ] ) ]
        }
    {
        [ ( column_list ) ] 
        [ <OUTPUT Clause> ]
        { VALUES ( { DEFAULT | NULL | expression } [ ,...n ] ) [ ,...n     ] 
        | derived_table       <<<<------- Look here ------------------------
        | execute_statement   <<<<------- Look here ------------------------
        | <dml_table_source>  <<<<------- Look here ------------------------
        | DEFAULT VALUES 
        }
    }
}
[;]

Cela devrait s'appliquer à tout autre SGBDR disponible sur place. Il est inutile de se souvenir de toute la syntaxe pour tous les produits IMO.

Faiz
la source
Je suis complètement en désaccord, je regarde ces déclarations de syntaxe depuis des années et je ne peux toujours pas en faire des têtes ou des queues. Les exemples sont beaucoup plus utiles
reggaeguitar
Ce n'est pas une réponse, c'est dire "lire la documentation" et c'est tout
reggaeguitar
12
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT  COLUMN_NAME
FROM    ANOTHER_TABLE_NAME 
WHERE CONDITION;
Gaurav
la source
@ggorlen Cela me semble assez évident
reggaeguitar
Elle a été signalée dans la file d'attente de révision comme une réponse uniquement codée. Je peux voir votre point ici, cependant - il n'y a pas grand-chose à dire dans le contexte de la plupart des réponses sur cette page maintenant que je le vois dans son environnement naturel.
ggorlen
9
select *
into tmp
from orders

Semble bien, mais ne fonctionne que si tmp n'existe pas (le crée et le remplit). (Serveur SQL)

Pour insérer dans la table tmp existante:

set identity_insert tmp on

insert tmp 
([OrderID]
      ,[CustomerID]
      ,[EmployeeID]
      ,[OrderDate]
      ,[RequiredDate]
      ,[ShippedDate]
      ,[ShipVia]
      ,[Freight]
      ,[ShipName]
      ,[ShipAddress]
      ,[ShipCity]
      ,[ShipRegion]
      ,[ShipPostalCode]
      ,[ShipCountry] )
      select * from orders

set identity_insert tmp off
Pavel
la source
9

Meilleure façon d'insérer plusieurs enregistrements à partir d'autres tables.

INSERT  INTO dbo.Users
            ( UserID ,
              Full_Name ,
              Login_Name ,
              Password
            )
            SELECT  UserID ,
                    Full_Name ,
                    Login_Name ,
                    Password
            FROM    Users_Table
            (INNER JOIN / LEFT JOIN ...)
            (WHERE CONDITION...)
            (OTHER CLAUSE)
Manish Vadher
la source
2

Si vous utilisez la route INSERT VALUES pour insérer plusieurs lignes, assurez-vous de délimiter les VALEURS en ensembles à l'aide de parenthèses, donc:

INSERT INTO `receiving_table`
  (id,
  first_name,
  last_name)
VALUES 
  (1002,'Charles','Babbage'),
  (1003,'George', 'Boole'),
  (1001,'Donald','Chamberlin'),
  (1004,'Alan','Turing'),
  (1005,'My','Widenius');

Sinon, MySQL objecte que "le nombre de colonnes ne correspond pas au nombre de valeurs à la ligne 1", et vous finissez par écrire un article trivial lorsque vous savez enfin quoi faire à ce sujet.

Sébastien
la source
6
La question est "insérer dans une table en utilisant l'entrée d'une autre table ". Comment votre réponse répond-elle à cette question?
Quality Catalyst
3
Eh ne soyez pas trop dur avec lui. Cela a répondu à ma question lorsque je parcourais les alentours. @QualityCatalyst
Cameron Belt
1

SI vous souhaitez insérer des données dans une table sans écrire le nom de la colonne.

INSERT INTO CUSTOMER_INFO
   (SELECT CUSTOMER_NAME,
           MOBILE_NO,
           ADDRESS
      FROM OWNER_INFO cm
     WHERE ID>100)

Où sont les tableaux:

            CUSTOMER_INFO               ||            OWNER_INFO
----------------------------------------||-------------------------------------
CUSTOMER_NAME | MOBILE_NO | ADDRESS     || CUSTOMER_NAME | MOBILE_NO | ADDRESS 
--------------|-----------|---------    || --------------|-----------|--------- 
      A       |     +1    |   DC        ||       B       |     +55   |   RR  

Résultat:

            CUSTOMER_INFO               ||            OWNER_INFO
----------------------------------------||-------------------------------------
CUSTOMER_NAME | MOBILE_NO | ADDRESS     || CUSTOMER_NAME | MOBILE_NO | ADDRESS 
--------------|-----------|---------    || --------------|-----------|--------- 
      A       |     +1    |   DC        ||       B       |     +55   |   RR
      B       |     +55   |   RR        ||
SMFazle Rabbi
la source
0

Dans informix, cela fonctionne comme Claude l'a dit:

INSERT INTO table (column1, column2) 
VALUES (value1, value2);    
Miroslav Savel
la source
0

Postgres prend en charge ensuite: créer la table company.monitor2 en tant que select * from company.monitor;

Kazakov Vsevolod
la source