แทรกลงใน ... ค่า (เลือก…จาก…)


1427

ฉันกำลังพยายามINSERT INTOตารางโดยใช้อินพุตจากตารางอื่น แม้ว่าสิ่งนี้จะเป็นไปได้ทั้งหมดสำหรับเอ็นจิ้นฐานข้อมูลจำนวนมาก แต่ฉันมักจะพยายามจดจำไวยากรณ์ที่ถูกต้องสำหรับเอ็นSQLจิ้นประจำวัน ( MySQL , Oracle , SQL Server , InformixและDB2 )

มีไวยากรณ์กระสุนเงินที่มาจากมาตรฐาน SQL (เช่นSQL-92 ) ที่จะให้ฉันใส่ค่าโดยไม่ต้องกังวลเกี่ยวกับฐานข้อมูลพื้นฐานหรือไม่


1
ตัวอย่างนี้ใช้งานได้: แทรกลงใน tag_zone select @ tag, zoneid, GETDATE (), @ positiong.STIntersects (รูปหลายเหลี่ยม) จากโซน
UğurGümüşhan

คำตอบ:


1611

ลอง:

INSERT INTO table1 ( column1 )
SELECT  col1
FROM    table2  

นี่คือมาตรฐาน ANSI SQL และควรทำงานกับ DBMS ใด ๆ

มันใช้งานได้กับ:

  • คำพยากรณ์
  • เซิร์ฟเวอร์ MS SQL
  • MySQL
  • Postgres
  • SQLite v3
  • Teradata
  • DB2
  • Sybase
  • Vertica
  • HSQLDB
  • H2
  • AWS RedShift
  • SAP HANA

947

คำตอบของ Claude Houle : ควรทำงานได้ดีและคุณสามารถมีคอลัมน์และข้อมูลอื่น ๆ ได้หลายรายการเช่นกัน:

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

ฉันใช้ไวยากรณ์นี้กับ Access, SQL 2000/2005 / Express, MySQL และ PostgreSQL เท่านั้นดังนั้นควรครอบคลุมสิ่งเหล่านั้น มันควรจะทำงานร่วมกับ SQLite3


1
เกิดอะไรขึ้นถ้าเงื่อนไขที่เปลี่ยนเป็น table2.country และส่งคืนจำนวนแถวที่มากกว่าหนึ่ง ฉันมีปัญหาที่คล้ายกันที่นี่: stackoverflow.com/questions/36030370/ …
vijayrana

1
ไม่ควรมีปัญหาในการแทรกมากกว่าหนึ่งแถว
rinukkusu

จำเป็นหรือไม่ที่เราจะต้องแทรกเข้าไปในคอลัมน์ทั้งหมดของตาราง
maheshmnj

1
@maheshmnj ไม่เฉพาะคอลัมน์ที่ตั้งค่าเป็นไม่เป็นโมฆะและไม่จำเป็นต้องมีค่าเริ่มต้นคอลัมน์อื่น ๆ จะถูกตั้งเป็นค่าเริ่มต้นหรือเป็นโมฆะ
รวิส

ขอบคุณสำหรับข้อมูล
maheshmnj

148

เพื่อรับค่าเดียวในค่าหลายค่าINSERTจากตารางอื่นฉันทำต่อไปนี้ใน SQLite3:

INSERT INTO column_1 ( val_1, val_from_other_table ) 
VALUES('val_1', (SELECT  val_2 FROM table_2 WHERE val_2 = something))

4
เพื่อความกระจ่าง: สิ่งนี้ไม่ถูกต้องสำหรับ SQLite3 ตามเอกสารข้อมูลแหล่งสำหรับINSERTเป็นอย่างใดอย่างหนึ่ง VALUESหรือSELECTคำสั่งไม่ใช่ทั้งสองอย่าง

2
มันเป็นความจริงเอกสารไม่ได้แสดง แต่มันใช้งานได้ ฉันคิดว่าการใช้คำสั่ง select แทนค่าจะทำให้อ่านได้ง่ายขึ้น
Banjocat

1
มันทำงานเพื่อระบุค่าในแถว แต่กรณีทั่วไปมากขึ้นต้องได้รับแถวจำนวนมาก
Luchostein

หาก val_1 ไม่เปลี่ยนแปลงในหลายแถวไวยากรณ์ต่อไปนี้อาจใช้ได้ใน SQLite3 หรือไม่ เลือก 'foo' some_column จาก some_table - ทำงานใน SQLServer 2014
Chris B

เอกสารไม่รายการนี้ (ตอนนี้?): รูปแบบนี้เป็นINSERT INTO ... VALUES ([expr], [expr], ...)และเป็นหนึ่งในเส้นทางที่[expr]เป็น{{NOT} EXISTS} ([select-stmt])- ทราบว่าวงเล็บรอบคำสั่งเลือกจะต้อง ( {}หมายถึงตัวเลือก)
zapl

64

ทั้งคำตอบที่ฉันเห็นว่าทำงานได้ดีใน Informix โดยเฉพาะและเป็น SQL มาตรฐานโดยทั่วไป นั่นคือสัญกรณ์:

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

ทำงานได้ดีกับ Informix และฉันคาดหวังว่า DBMS ทั้งหมด (เมื่อ 5 ปีที่ผ่านมานี้เป็นสิ่งที่ MySQL ไม่สนับสนุนเสมอไปตอนนี้มันมีการสนับสนุนที่ดีสำหรับไวยากรณ์ SQL มาตรฐานประเภทนี้และ AFAIK มันจะทำงานได้ดีกับสัญลักษณ์นี้) รายการคอลัมน์ เป็นทางเลือก แต่ระบุคอลัมน์เป้าหมายตามลำดับดังนั้นคอลัมน์แรกของผลลัพธ์ของ SELECT จะไปยังคอลัมน์แรกที่แสดงรายการ ฯลฯ หากไม่มีรายการคอลัมน์คอลัมน์แรกของผลลัพธ์ของ SELECT จะเข้าสู่ คอลัมน์แรกของตารางเป้าหมาย

สิ่งที่สามารถแตกต่างกันระหว่างระบบคือสัญกรณ์ที่ใช้ระบุตารางในฐานข้อมูลที่ต่างกัน - มาตรฐานไม่มีอะไรจะพูดเกี่ยวกับการดำเนินการระหว่างฐานข้อมูล ด้วย Informix คุณสามารถใช้สัญลักษณ์ต่อไปนี้เพื่อระบุตาราง:

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

นั่นคือคุณอาจระบุฐานข้อมูลระบุเซิร์ฟเวอร์ที่โฮสต์ฐานข้อมูลนั้นหากไม่ได้อยู่ในเซิร์ฟเวอร์ปัจจุบันตามด้วยเจ้าของตัวเลือกจุดและสุดท้ายชื่อตารางจริง มาตรฐาน SQL ใช้คำว่าสกีมาสำหรับสิ่งที่ Informix เรียกว่าเจ้าของ ดังนั้นใน Informix สัญลักษณ์ใด ๆ ต่อไปนี้สามารถระบุตาราง:

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

ไม่จำเป็นต้องอ้างถึงเจ้าของโดยทั่วไป อย่างไรก็ตามหากคุณใช้เครื่องหมายคำพูดคุณจะต้องสะกดชื่อเจ้าของให้ถูกต้อง นั่นคือ:

someone.table
"someone".table
SOMEONE.table

ทั้งหมดระบุตารางเดียวกัน ด้วย Informix มีความยุ่งยากเล็กน้อยกับฐานข้อมูล MODE ANSI ซึ่งโดยทั่วไปชื่อเจ้าของจะถูกแปลงเป็นตัวพิมพ์ใหญ่ (informix เป็นข้อยกเว้น) นั่นคือในฐานข้อมูล MODE ANSI (ไม่ได้ใช้กันทั่วไป) คุณสามารถเขียน:

CREATE TABLE someone.table ( ... )

และชื่อเจ้าของในแคตตาล็อกระบบจะเป็น "คน" แทนที่จะเป็น "ใครบางคน" หากคุณใส่ชื่อเจ้าของในเครื่องหมายคำพูดคู่มันจะทำหน้าที่เหมือนตัวระบุที่คั่น ด้วย SQL มาตรฐานตัวระบุที่คั่นสามารถใช้หลาย ๆ ที่ได้ ด้วย Informix คุณสามารถใช้งานได้เฉพาะกับชื่อเจ้าของ - ในบริบทอื่น ๆ Informix จะใช้ทั้งสตริงที่มีการเสนอราคาเดียวและการเสนอราคาสองครั้งเป็นสตริงแทนที่จะแยกสตริงที่เสนอราคาเดียวเป็นสตริงและสตริงที่มีการเสนอราคาสองครั้งเป็นตัวระบุที่คั่น (แน่นอนว่าเพื่อความสมบูรณ์มีตัวแปรสภาพแวดล้อม DELIMIDENT ที่สามารถตั้งค่า - เป็นค่าใดก็ได้ แต่ Y ปลอดภัยที่สุด - เพื่อระบุว่าอัญประกาศคู่ล้อมรอบตัวระบุที่คั่นเสมอและอัญประกาศล้อมรอบสตริงเสมอ)

โปรดทราบว่า MS SQL Server จัดการเพื่อใช้ [ตัวคั่นคั่น] ล้อมรอบในวงเล็บเหลี่ยม มันดูแปลกสำหรับฉันและแน่นอนไม่ได้เป็นส่วนหนึ่งของมาตรฐาน SQL


40

หากต้องการเพิ่มบางสิ่งในคำตอบแรกเมื่อเราต้องการเพียงไม่กี่ระเบียนจากตารางอื่น (ในตัวอย่างนี้มีเพียงหนึ่งรายการเท่านั้น):

INSERT INTO TABLE1
(COLUMN1, COLUMN2, COLUMN3, COLUMN4) 
VALUES (value1, value2, 
(SELECT COLUMN_TABLE2 
FROM TABLE2
WHERE COLUMN_TABLE2 like "blabla"),
value4);

4
วิธีการนี้ใช้กับแบบสอบถามย่อยดังกล่าวที่เลือกเพียงหนึ่งคอลัมน์เท่านั้น ในกรณีของแบบสอบถามย่อยหลายคอลัมน์จะเกิดข้อผิดพลาด 'แบบสอบถามย่อยจะส่งกลับเพียงหนึ่งคอลัมน์' ยอมรับคำตอบของ @ travis แล้ว
snowfox

34

ฐานข้อมูลส่วนใหญ่เป็นไปตามไวยากรณ์พื้นฐาน

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

ทุกฐานข้อมูลฉันได้ใช้ทำตามรูปแบบนี้คือDB2, SQL Server, MY SQL,PostgresQL


34

แทนที่จะVALUESเป็นส่วนหนึ่งของINSERTแบบสอบถามให้ใช้SELECTแบบสอบถามดังนี้

INSERT INTO table1 ( column1 , 2, 3... )
SELECT col1, 2, 3... FROM table2

32

สองวิธีในการแทรกเข้ากับแบบสอบถามย่อยที่เลือก

  1. ด้วย SELECT แบบสอบถามย่อยผลกลับมาพร้อมกับหนึ่งแถว
  2. ด้วย SELECT แบบสอบถามย่อยผลกลับมาพร้อมกับหลายแถว

1. แนวทางสำหรับด้วย SELECT ผลแบบสอบถามย่อยกลับมาพร้อมกับหนึ่งแถว

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

ในกรณีนี้มันจะถือว่าแบบสอบถามย่อยย่อย SELECT ส่งคืนผลลัพธ์เพียงหนึ่งแถวโดยยึดตามเงื่อนไข WHERE หรือฟังก์ชันการรวม SQL เช่น SUM, MAX, AVG เป็นต้นมิฉะนั้นจะเกิดข้อผิดพลาด

2. แนวทางสำหรับด้วย SELECT แบบสอบถามย่อยผลกลับมาพร้อมกับหลายแถว

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

วิธีที่สองจะใช้งานได้กับทั้งสองกรณี


29

สิ่งนี้สามารถทำได้โดยไม่ต้องระบุคอลัมน์ในINSERT INTOส่วนถ้าคุณกำลังจัดหาค่าสำหรับคอลัมน์ทั้งหมดในSELECTส่วน

สมมุติว่า table1 มีสองคอลัมน์ แบบสอบถามนี้ควรใช้งานได้:

INSERT INTO table1
SELECT  col1, col2
FROM    table2

WOULD นี้ไม่ทำงาน ( col2ไม่ได้ระบุค่าไว้):

INSERT INTO table1
SELECT  col1
FROM    table2

ฉันใช้ MS SQL Server ฉันไม่รู้ว่า RDMS อื่นทำงานอย่างไร


24

นี่เป็นอีกตัวอย่างหนึ่งที่ใช้ค่าที่มีการเลือก:

INSERT INTO table1(desc, id, email) 
SELECT "Hello World", 3, email FROM table2 WHERE ...

คำตอบเก่าและยังมีประโยชน์ สวยเรียบง่ายและชัดเจน แต่ครอบคลุมความต้องการของฉันอย่างแน่นอน ขอบคุณ!
เซบาสเตียน Kaczmarek

21

การแทรกอย่างง่ายเมื่อทราบลำดับคอลัมน์ของตาราง:

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

คอลัมน์แทรกที่กล่าวถึงอย่างง่าย:

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

การแทรกจำนวนมากเมื่อจำนวนคอลัมน์ที่เลือกของตาราง (# table2) เท่ากับตารางการแทรก (ตารางที่ 1)

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

การแทรกจำนวนมากเมื่อคุณต้องการแทรกลงในคอลัมน์ที่ต้องการของตาราง (ตารางที่ 1) เท่านั้น:

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

17

นี่เป็นอีกตัวอย่างหนึ่งที่แหล่งที่มาถูกนำมาใช้มากกว่าหนึ่งตาราง:

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;

17

เพียงใช้วงเล็บสำหรับคำสั่งย่อยSELECTใน INSERT ตัวอย่างเช่นนี้:

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

ขอบคุณ @Das มันใช้งานได้สำหรับฉัน ....
Raj G

16

นี่คือวิธีแทรกจากหลายตาราง ตัวอย่างเฉพาะนี้คือที่ที่คุณมีตารางการแมปในหลาย ๆ สถานการณ์:

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'

(ฉันทราบว่าการจับคู่กับชื่อนักเรียนอาจส่งคืนค่ามากกว่าหนึ่งค่า แต่คุณจะได้รับแนวคิดการจับคู่กับสิ่งอื่นที่ไม่ใช่ Id เป็นสิ่งจำเป็นเมื่อ Id เป็นคอลัมน์ข้อมูลประจำตัวและไม่ทราบ)



14

คุณสามารถลองได้ถ้าคุณต้องการแทรกคอลัมน์ทั้งหมดโดยใช้SELECT * INTOตาราง

SELECT  *
INTO    Table2
FROM    Table1;

13

ฉันชอบสิ่งต่อไปนี้ใน 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

มันกำจัดขั้นตอนของการเพิ่มการตั้งค่าแทรก () และคุณเพียงแค่เลือกค่าที่ไปในตาราง


13

สิ่งนี้ใช้ได้กับฉัน:

insert into table1 select * from table2

ประโยคนี้แตกต่างจาก Oracle เล็กน้อย


12

สำหรับ Microsoft SQL Server ฉันจะแนะนำให้เรียนรู้การตีความ SYNTAX ที่มีให้ใน MSDN ด้วย Google มันง่ายกว่าที่เคยเพื่อค้นหาไวยากรณ์

สำหรับกรณีนี้ลอง

Google: แทรกเว็บไซต์: microsoft.com

ผลลัพธ์แรกจะเป็นhttp://msdn.microsoft.com/en-us/library/ms174335.aspx

เลื่อนลงไปที่ตัวอย่าง ("การใช้ตัวเลือก SELECT และ EXECUTE เพื่อแทรกข้อมูลจากตารางอื่น") หากคุณพบว่าเป็นการยากที่จะตีความไวยากรณ์ที่ให้ไว้ที่ด้านบนของหน้า

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

สิ่งนี้ควรใช้กับ RDBMS อื่นที่มีอยู่ ไม่มีจุดในการจดจำไวยากรณ์ทั้งหมดสำหรับผลิตภัณฑ์ทั้งหมด IMO


ฉันไม่เห็นด้วยอย่างสมบูรณ์ฉันได้ดูงบไวยากรณ์เหล่านั้นมาหลายปีแล้วและยังไม่สามารถทำให้หัวหรือก้อยได้ ตัวอย่างมีประโยชน์มากขึ้น
reggaeguitar

นี้ไม่ได้คำตอบก็พูดว่า "อ่านเอกสาร" และที่เกี่ยวกับมัน
reggaeguitar

12
INSERT INTO FIRST_TABLE_NAME (COLUMN_NAME)
SELECT  COLUMN_NAME
FROM    ANOTHER_TABLE_NAME 
WHERE CONDITION;

@ggorlen มันดูเหมือนตัวเองที่เห็นได้ชัดสำหรับฉัน
reggaeguitar

มันถูกตั้งค่าสถานะในคิวการตรวจสอบเป็นคำตอบรหัสเท่านั้น แม้ว่าฉันจะเห็นประเด็นของคุณที่นี่ - ไม่มีอะไรจะพูดมากนักในบริบทของคำตอบส่วนใหญ่ในหน้านี้ตอนนี้ที่ฉันเห็นมันในสภาพแวดล้อมตามธรรมชาติ
ggorlen

9
select *
into tmp
from orders

ดูดี แต่ใช้งานได้หาก tmp ไม่มีอยู่เท่านั้น (สร้างและเติม) (เซิร์ฟเวอร์ SQL)

หากต้องการแทรกลงในตาราง 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

9

วิธีที่ดีที่สุดในการแทรกหลายระเบียนจากตารางอื่น ๆ

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)

2

หากคุณไปเส้นทาง INSERT VALUES เพื่อแทรกหลายแถวตรวจสอบให้แน่ใจว่าได้กำหนดค่า VALUES เป็นชุดโดยใช้วงเล็บดังนั้น:

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

มิฉะนั้นวัตถุ MySQL ที่ "การนับคอลัมน์ไม่ตรงกับการนับค่าที่แถว 1" และคุณจบลงด้วยการเขียนโพสต์เล็กน้อยเมื่อในที่สุดคุณก็คิดออกว่าจะทำอย่างไรกับมัน


6
คำถามคือ "แทรกลงในตารางโดยใช้อินพุตจากตารางอื่น " คำตอบของคุณตอบคำถามนี้อย่างไร
คุณภาพ

3
เอ๊ะอย่ายากเกินไปกับเขา มันตอบคำถามของฉันเมื่อฉัน googling รอบ ๆ @QualityCatalyst
Cameron Belt

1

หากคุณต้องการแทรกข้อมูลลงในตารางโดยไม่ต้องการเขียนชื่อคอลัมน์

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

ตารางอยู่ที่ไหน:

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

ผลลัพธ์:

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


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.