Wstaw do… wartości (WYBIERZ… OD…)

1427

Próbuję do INSERT INTOtabeli przy użyciu danych wejściowych z innej tabeli. Chociaż jest to całkowicie wykonalne w przypadku wielu silników baz danych, zawsze wydaje mi się, że mam trudności z zapamiętaniem poprawnej składni SQLsilnika tego dnia ( MySQL , Oracle , SQL Server , Informix i DB2 ).

Czy istnieje składnia srebrnej kuli pochodząca ze standardu SQL (na przykład SQL-92 ), który pozwoliłby mi wstawiać wartości bez martwienia się o bazową bazę danych?

Claude Houle
źródło
1
ten przykład działa: wstaw do tag_zone select @ tag, zoneid, GETDATE (), @ positiong.STIntersects (wielobok) ze strefy
Uğur Gümüşhan

Odpowiedzi:

1611

Próbować:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

Jest to standardowy ANSI SQL i powinien działać na każdym DBMS

Zdecydowanie działa na:

  • Wyrocznia
  • MS SQL Server
  • MySQL
  • Postgres
  • SQLite v3
  • Teradata
  • DB2
  • Sybase
  • Vertica
  • HSQLDB
  • H2
  • AWS RedShift
  • SAP HANA
Claude Houle
źródło
945

Odpowiedź Claude'a Houle'a : powinna działać dobrze, możesz także mieć wiele kolumn i inne dane:

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

Użyłem tej składni tylko z Access, SQL 2000/2005 / Express, MySQL i PostgreSQL, więc należy je omówić. Powinien także współpracować z SQLite3.

Travis
źródło
1
co jeśli warunek where zmienił się na table2.country i zwraca liczbę wierszy większą niż jeden? Mam podobny problem tutaj: stackoverflow.com/questions/36030370/…
vijayrana
1
Nie powinno być problemu z wstawieniem więcej niż jednego wiersza.
rinukkusu 11.04.16
czy konieczne jest wstawienie do wszystkich kolumn tabeli
maheshmnj
1
@maheshmnj nie, tylko kolumny, które są ustawione na NIE NULL i nie ma potrzeby dodawania wartości domyślnej, wszelkie inne kolumny zostaną ustawione na wartości domyślne lub NULL
travis
dzięki za informacje
maheshmnj
148

Aby uzyskać tylko jedną wartość z wielu wartości INSERTz innej tabeli, wykonałem następujące czynności w 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
źródło
4
Tylko dla wyjaśnienia: jest to niepoprawne dla SQLite3. Zgodnie z dokumentacją , danymi źródłowymi INSERTjest jedno VALUES lub jedno SELECTzdanie, a nie jedno i drugie.
2
To prawda, że ​​dokumentacja tego nie wymienia, ale działa. Niezależnie od tego uważam, że użycie instrukcji select zamiast wartości czyni ją bardziej czytelną.
Banjocat
1
Działa w celu określenia wartości w wierszu, ale bardziej ogólny przypadek wymaga uzyskania dużej liczby wierszy.
Luchostein
Jeśli val_1 nie zmienia się między wierszami, to następująca składnia może działać w SQLite3? wybierz 'foo', some_column z some_table - działa w SQLServer 2014
Chris B
Dokumentacja zawiera to (teraz?): Ta składnia jest, INSERT INTO ... VALUES ([expr], [expr], ...)a jedną ze ścieżek [expr]jest {{NOT} EXISTS} ([select-stmt])- zauważ, że paranteza wokół instrukcji select jest wymagana ( {}co oznacza opcjonalne)
zapl
64

Obie odpowiedzi, które widzę, działają dobrze w szczególności w Informix i są w zasadzie standardowym SQL. Oznacza to, że:

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

działa dobrze z Informix i, oczekiwałbym, z całym DBMS. (Kiedyś 5 lat temu było to coś, czego MySQL nie zawsze obsługiwał; teraz ma przyzwoitą obsługę tego rodzaju standardowej składni SQL i, AFAIK, działałoby OK na tej notacji.) Lista kolumn jest opcjonalny, ale wskazuje kolumny docelowe w sekwencji, więc pierwsza kolumna wyniku SELECT przejdzie do pierwszej wymienionej kolumny itp. W przypadku braku listy kolumn pierwsza kolumna wyniku SELECT przechodzi do pierwsza kolumna tabeli docelowej.

To, co może różnić się między systemami, to notacja używana do identyfikacji tabel w różnych bazach danych - standard nie ma nic do powiedzenia na temat operacji między bazami danych (nie mówiąc już o między DBMS). Dzięki Informix możesz użyć następującej notacji do identyfikacji tabeli:

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

Oznacza to, że możesz określić bazę danych, opcjonalnie identyfikując serwer, który obsługuje tę bazę danych, jeśli nie ma jej na bieżącym serwerze, a następnie opcjonalny właściciel, kropka i na koniec rzeczywista nazwa tabeli. Standard SQL używa terminu schemat do tego, co Informix nazywa właścicielem. Dlatego w Informix dowolne z poniższych oznaczeń mogą identyfikować tabelę:

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

Zasadniczo nie trzeba podawać właściciela; jeśli jednak używasz cudzysłowów, musisz poprawnie wpisać nazwę właściciela - w rozróżnianiu wielkości liter ma znaczenie. To jest:

someone.table
"someone".table
SOMEONE.table

wszystkie identyfikują ten sam stół. W przypadku Informix istnieje niewielka komplikacja z bazami danych MODE ANSI, w których nazwy właścicieli są zazwyczaj konwertowane na wielkie litery (wyjątek stanowi informix). Oznacza to, że w bazie danych MODE ANSI (niezbyt często używane) możesz napisać:

CREATE TABLE someone.table ( ... )

a nazwa właściciela w katalogu systemowym brzmiałaby „SOMEONE”, a nie „ktoś”. Jeśli umieścisz nazwę właściciela w podwójnych cudzysłowach, będzie to działało jak rozdzielany identyfikator. W standardowym języku SQL ograniczników można używać w wielu miejscach. Dzięki Informix możesz używać ich tylko wokół nazw właścicieli - w innych kontekstach Informix traktuje zarówno ciągi jedno-, jak i podwójnie cudzysłowy jako ciągi, a nie oddzielając ciągów jedno- i dwu-cytatowych jako ciągi, a ciągów podwójnych jako rozdzielane identyfikatory. (Oczywiście, dla kompletności, istnieje zmienna środowiskowa DELIMIDENT, którą można ustawić - na dowolną wartość, ale Y jest najbezpieczniejszy - aby wskazać, że podwójne cudzysłowy zawsze otaczają identyfikatory rozdzielane ograniczeniami, a pojedyncze cudzysłowy zawsze otaczają ciągi znaków.)

Zauważ, że MS SQL Server potrafi wykorzystać [identyfikatory rozdzielane] w nawiasach kwadratowych. Wydaje mi się to dziwne i na pewno nie jest częścią standardu SQL.

Jonathan Leffler
źródło
40

Aby dodać coś w pierwszej odpowiedzi, gdy chcemy tylko kilku rekordów z innej tabeli (w tym przykładzie tylko jednej):

INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4) 
VALUES (value1, value2, 
(SELECT COLUMN_TABLE2 
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);
Weslor
źródło
4
To podejście dotyczy tylko takiego podzapytania, że ​​wybrano tylko jedną kolumnę. W przypadku podzapytania z wieloma kolumnami zostanie zgłoszony błąd „podzapytanie musi zwrócić tylko jedną kolumnę”. Przyjmij odpowiedź @ travis.
snowfox
34

Większość baz danych ma podstawową składnię,

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

Każda baza danych Użyłem obserwować tą składnię mianowicie DB2, SQL Server, MY SQL,PostgresQL

Santhosh
źródło
34

Zamiast VALUESczęści INSERTzapytania wystarczy użyć SELECTzapytania jak poniżej.

INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2
logan
źródło
32

Dwa podejścia do wstawiania za pomocą wybranego zapytania częściowego.

  1. Z SELECT podkwerenda zwraca wyniki z Jednym wierszem .
  2. Z SELECT podkwerenda zwraca wyniki z wieloma wierszami .

1. Podejście do przy użyciu zapytania SELECT zwracającego wyniki z jednym wierszem .

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

W tym przypadku zakłada się, że zapytanie podrzędne WYBIERZ zwraca tylko jeden wiersz wyniku na podstawie GDZIE warunku lub funkcji agregujących SQL, takich jak SUMA, MAKS, AVG itp. W przeciwnym razie wygeneruje błąd

2. Podejście do zapytania Z SELECT zwraca wyniki z wieloma wierszami .

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

Drugie podejście będzie działać w obu przypadkach.

Mohammed Safeer
źródło
29

Można to zrobić bez określania kolumn w INSERT INTOczęści, jeśli podajesz wartości dla wszystkich kolumn w SELECTczęści.

Powiedzmy, że table1 ma dwie kolumny. To zapytanie powinno działać:

INSERT INTO table1
SELECT  col1, col2
FROM    table2

To NIE MOŻE działać (wartość col2nie jest określona):

INSERT INTO table1
SELECT  col1
FROM    table2

Używam MS SQL Server. Nie wiem, jak działają inne RDMS.

Northben
źródło
24

To kolejny przykład z użyciem wartości z select:

INSERT INTO table1(desc, id, email) 
SELECT "Hello World", 3, email FROM table2 WHERE ...
Sarvar Nishonboev
źródło
Stara odpowiedź i wciąż przydatna. Całkiem proste i oczywiste, ale dokładnie pokrywa moje potrzeby. Dzięki!
Sebastian Kaczmarek
21

Proste wstawianie, gdy znana jest sekwencja kolumn tabeli:

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

Prosta wstawka z kolumną:

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

Wstawianie zbiorcze, gdy liczba wybranych kolumn tabeli (# tabela2) jest równa tabeli wstawiania (tabela1)

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

Wstawianie zbiorcze, jeśli chcesz wstawić tylko do żądanej kolumny tabeli (tabela 1):

    Insert into Table1 (Column1,Column2 ....Desired Column from Table1)  
    Select Column1,Column2..desired column from #table2
       from #table2
RameezAli
źródło
17

Oto kolejny przykład, w którym źródło jest pobierane przy użyciu więcej niż jednej tabeli:

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
źródło
17

Wystarczy użyć nawiasów dla klauzuli SELECT w INSERT. Na przykład tak:

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'
);
Dasikely
źródło
Dzięki @Das To działa dla mnie ....
Raj G
16

Oto jak wstawić z wielu tabel. W tym konkretnym przykładzie masz tabelę mapowania w scenariuszu wiele do wielu:

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'

(Zdaję sobie sprawę, że dopasowanie nazwiska studenta może zwrócić więcej niż jedną wartość, ale masz pomysł. Dopasowanie czegoś innego niż identyfikator jest konieczne, gdy identyfikator jest kolumną tożsamości i jest nieznany).

Ciaran Bruen
źródło
14
INSERT INTO yourtable
SELECT fielda, fieldb, fieldc
FROM donortable;

Działa to na wszystkich DBMS

Matt
źródło
14

Możesz spróbować, jeśli chcesz wstawić całą kolumnę za pomocą SELECT * INTOtabeli.

SELECT  *
INTO    Table2
FROM    Table1;
Teoria Bharata
źródło
13

Właściwie wolę następujące w 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

Eliminuje to etap dodawania zestawu Insert (), a Ty po prostu wybierasz, które wartości mają się znaleźć w tabeli.

Grungondola
źródło
13

To działało dla mnie:

insert into table1 select * from table2

To zdanie jest nieco inne niż Oracle.

elijah7
źródło
12

W przypadku Microsoft SQL Server zalecę nauczenie się interpretowania SYNTAX podanego na MSDN. W Google łatwiej niż kiedykolwiek szukać składni.

W tym konkretnym przypadku spróbuj

Google: wstaw witrynę: microsoft.com

Pierwszym wynikiem będzie http://msdn.microsoft.com/en-us/library/ms174335.aspx

przewiń w dół do przykładu („Używanie opcji WYBIERZ i WYKONAJ, aby wstawić dane z innych tabel”), jeśli masz trudności z interpretacją składni podanej na górze strony.

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

Powinno to mieć zastosowanie do wszelkich innych dostępnych RDBMS. Nie ma sensu zapamiętywać całej składni dla wszystkich produktów IMO.

Faiz
źródło
Zupełnie się nie zgadzam, od lat patrzę na te instrukcje składniowe i nadal nie mogę ich zrozumieć. Przykłady są znacznie bardziej przydatne
reggaeguitar
To nie jest odpowiedź, mówi „przeczytaj dokumenty” i tyle o tym
reggaeguitar
12
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT  COLUMN_NAME
FROM    ANOTHER_TABLE_NAME 
WHERE CONDITION;
Gauraw
źródło
@ggorlen Wygląda mi to dość oczywisto
reggaeguitar
Oznaczono go w kolejce recenzji jako odpowiedź tylko do kodu. Widzę jednak tutaj twój punkt widzenia - nie ma wiele do powiedzenia w kontekście większości odpowiedzi na tej stronie, skoro widzę to w naturalnym środowisku.
ggorlen,
9
select *
into tmp
from orders

Wygląda ładnie, ale działa tylko wtedy, gdy tmp nie istnieje (tworzy go i wypełnia). (Serwer SQL)

Aby wstawić do istniejącej tabeli tmp:

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
źródło
9

Najlepszy sposób na wstawienie wielu rekordów z dowolnych innych tabel.

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
źródło
2

Jeśli pójdziesz ścieżką WSTAW WARTOŚCI, aby wstawić wiele wierszy, upewnij się, że WARTOŚCI są rozdzielane w zestawy za pomocą nawiasów, więc:

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');

W przeciwnym razie obiekty MySQL, które „Liczba kolumn nie zgadza się z liczbą wartości w wierszu 1”, a ty w końcu piszesz trywialny post, kiedy wreszcie zastanawiasz się, co z tym zrobić.

Sebastian
źródło
6
Pytanie brzmi: „wstaw do tabeli przy użyciu danych wejściowych z innej tabeli ”. Jak twoja odpowiedź odpowiada na to pytanie?
Quality Catalyst
3
Eh, nie bądź dla niego zbyt surowy. Odpowiadało na moje pytanie, kiedy googlowałem. @QualityCatalyst
Cameron Belt
1

JEŚLI chcesz wstawić jakieś dane do tabeli bez potrzeby wpisywania nazwy kolumny.

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

Gdzie są tabele:

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

Wynik:

            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
źródło
0

W informix działa tak, jak powiedział Claude:

INSERT INTO table (column1, column2) 
VALUES (value1, value2);    
Miroslav Savel
źródło
0

Następnie obsługuje Postgres: utwórz tabelę company.monitor2 jako wybierz * z company.monitor;

Kazakow Wsiewołod
źródło