จะอัพเดทสองตารางในหนึ่งคำสั่งใน SQL Server 2005 ได้อย่างไร


193

ฉันต้องการอัปเดตสองตารางในคราวเดียว ฉันจะทำเช่นนั้นใน SQL Server 2005 ได้อย่างไร

UPDATE 
  Table1, 
  Table2
SET 
  Table1.LastName='DR. XXXXXX', 
  Table2.WAprrs='start,stop'
FROM 
  Table1 T1, 
  Table2 T2
WHERE 
  T1.id = T2.id
AND 
  T1.id = '010008'

4
มันจะช่วยถ้าคุณอธิบายว่าทำไม
Eric Mickelsen

2
ฉันกลัวว่า SQL Server 2005 จะไม่รองรับการอัปเดตหลายตารางในการสืบค้นเดียว
ซิงห์

คำตอบ:


195

คุณไม่สามารถอัปเดตหลายตารางในหนึ่งชุดคำสั่งอย่างไรก็ตามคุณสามารถใช้ธุรกรรมเพื่อให้แน่ใจว่าUPDATEคำสั่งสองรายการได้รับการปฏิบัติแบบอะตอม คุณยังสามารถแบทช์ให้เพื่อหลีกเลี่ยงการไปกลับ

BEGIN TRANSACTION;

UPDATE Table1
  SET Table1.LastName = 'DR. XXXXXX' 
FROM Table1 T1, Table2 T2
WHERE T1.id = T2.id
and T1.id = '011008';

UPDATE Table2
SET Table2.WAprrs = 'start,stop'
FROM Table1 T1, Table2 T2
WHERE T1.id = T2.id
and T1.id = '011008';

COMMIT;

ที่จริงแล้วฉันกำลังอัพเดทบันทึกของสองตารางนี้จากสิ่งล่อใจอื่น ล่อลวงมีลิงค์ไปยัง table1 แต่ไม่ใช่ table2 ฉันจะอัปเดตระเบียนเดียวกันของ Table2 ได้อย่างไร ฉันจะเชื่อมโยงมันได้อย่างไร
Jango

@unknown: ขึ้นอยู่กับความคิดเห็นของคุณคุณจะต้องเข้าร่วมทั้ง Table1 และ Table2 เมื่อคุณอัปเดต Table2 หากแบบสอบถามการปรับปรุงของคุณต้องการคีย์จากตารางที่สาม ไม่ว่าคุณจะยังคงต้องทำการอัพเดตสองอย่างแยกกัน
LBushkin

3
อาจไม่เกี่ยวข้อง: สิ่งนี้จะไม่สามารถใช้งานได้กับ MySQL เพราะไวยากรณ์การอัปเดตสำหรับ mysql นั้นแตกต่างกัน คุณต้องไปอัปเดต Table1, Table2 SET Table1.LastName = 'DR XXXXXX 'WHERE T1.id = T2.id
Juan Vilar

เราจำเป็นต้องรักษาคีย์หลักและความสัมพันธ์กับคีย์ต่างประเทศหรือไม่
srinivas gowda

2
คุณควรวางงบการอัพเดทไว้ใน try / catch block เพื่อหลีกเลี่ยงการอัพเดทบางส่วนในกรณีที่เกิดข้อผิดพลาด ดูคำถามนี้: stackoverflow.com/questions/1749719/…
mechatroner

84

คุณไม่สามารถอัปเดตสองตารางพร้อมกัน แต่คุณสามารถเชื่อมโยงการอัปเดตเข้ากับส่วนแทรกโดยใช้OUTPUT INTOและคุณสามารถใช้เอาต์พุตนี้เป็นการเข้าร่วมสำหรับการอัปเดตที่สอง:

DECLARE @ids TABLE (id int);
BEGIN TRANSACTION

UPDATE Table1 
SET Table1.LastName = 'DR. XXXXXX'  
OUTPUT INSERTED.id INTO @ids
WHERE Table1.field = '010008';

UPDATE Table2 
SET Table2.WAprrs = 'start,stop' 
FROM Table2 
JOIN @ids i on i.id = Table2.id;

COMMIT;

ผมเปลี่ยนตัวอย่างของคุณสภาพเป็นบางสาขาอื่นมากกว่าWHERE idถ้ามันidที่คุณไม่จำเป็นต้องแฟนซีนี้OUTPUTคุณสามารถเพียงตารางที่สองสำหรับเดียวกันUPDATEid='010008'


นี่คือคำตอบที่ดีที่สุดและควรได้รับการโหวตให้เป็นคำตอบที่แท้จริงของคำถามเดิม ขอบคุณ. มันใช้งานได้สำหรับฉัน
Fandango68

1
คือการที่T1.fieldควรจะเป็นTable1.field?
WAF

22

ขออภัย, คุณไม่สามารถทำได้ หากต้องการอัปเดตแอตทริบิวต์ในสองตารางที่แตกต่างกันคุณจะต้องดำเนินการสองข้อความแยกต่างหาก แต่พวกเขาสามารถอยู่ในชุด (ชุดของ SQL ที่ส่งไปยังเซิร์ฟเวอร์ในหนึ่งรอบการเดินทาง)


2
เอ้ย! ฉันควรใช้คำขอโทษบ่อยขึ้นสำหรับความรุ่งโรจน์เพิ่มเติม: P
Fandango68

14

คำตอบสั้น ๆ นั่นคือ ในขณะที่คุณสามารถป้อนหลายตารางในส่วนfromคำสั่งการปรับปรุงคุณสามารถระบุได้เพียงตารางเดียวหลังจากupdateคำหลัก แม้ว่าคุณจะเขียนมุมมอง "updatable" (ซึ่งเป็นเพียงมุมมองที่ตามหลังข้อ จำกัด บางอย่าง) การปรับปรุงเช่นนี้จะล้มเหลว นี่คือคลิปที่เกี่ยวข้องจากเอกสาร MSDN (เน้นเป็นของฉัน)

อัพเดท (Transact-SQL)

มุมมองที่อ้างอิงโดย table_or_view_name ต้องสามารถอัปเดตได้และอ้างอิงหนึ่งตารางฐานในส่วนคำสั่ง FROM ของมุมมอง สำหรับข้อมูลเพิ่มเติมเกี่ยวกับมุมมองที่อัพเดตได้ดูสร้างมุมมอง (Transact-SQL)

สร้างมุมมอง (Transact-SQL)

คุณสามารถปรับเปลี่ยนข้อมูลของตารางพื้นฐานผ่านมุมมองตราบเท่าที่เงื่อนไขต่อไปนี้เป็นจริง:

  • การปรับเปลี่ยนใด ๆ รวมทั้ง UPDATE, INSERT, และงบลบต้องอ้างอิงคอลัมน์จากเพียงตารางฐานหนึ่ง
  • คอลัมน์ที่กำลังแก้ไขในมุมมองจะต้องอ้างอิงข้อมูลพื้นฐานในคอลัมน์ตารางโดยตรง คอลัมน์ไม่สามารถรับได้ด้วยวิธีอื่นเช่นผ่านต่อไปนี้:
    • ฟังก์ชั่นรวม: AVG, COUNT, SUM, MIN, MAX, จัดกลุ่ม, STDEV, STDEVP, VAR และ VARP
    • การคำนวณ คอลัมน์ไม่สามารถคำนวณได้จากนิพจน์ที่ใช้คอลัมน์อื่น คอลัมน์ที่เกิดขึ้นโดยใช้ตัวดำเนินการกำหนดค่า UNION, UNION ALL, CROSSJOIN, EXCEPT และ INTERSECT จำนวนการคำนวณและไม่สามารถอัปเดตได้
  • คอลัมน์ที่กำลังแก้ไขจะไม่ได้รับผลกระทบจากคำสั่ง GROUP BY, HAVING หรือ DISTINCT
  • TOP ไม่ได้ใช้ที่ใดก็ได้ใน select_statement ของมุมมองพร้อมกับส่วนคำสั่ง WITH CHECK OPTION

คุณควรพิจารณาใช้คำสั่ง SQL สองคำสั่งที่แตกต่างกันภายในธุรกรรมตามตัวอย่างของ LBushkin

UPDATE: การยืนยันดั้งเดิมของฉันที่คุณสามารถอัปเดตหลายตารางในมุมมองที่อัปเดตได้ผิด บน SQL Server 2005 และ 2012 มันจะสร้างข้อผิดพลาดต่อไปนี้ ฉันแก้ไขคำตอบของฉันเพื่อสะท้อนสิ่งนี้แล้ว

Msg 4405, Level 16, State 1, Line 1

View or function 'updatable_view' is not updatable because the modification affects multiple base tables.


1
ในขณะที่มันเป็นไปไม่ได้ที่จะปรับปรุงดูวัตถุที่จะส่งผลกระทบต่อหลายตารางคุณสามารถสร้างแทนที่จะเรียกซึ่งทำลายต้นฉบับในงบเฉพาะกิจการ (ที่มีผลต่อหนึ่งตารางแต่ละคน):INSTEAD OF Specifies that the DML trigger is executed instead of the triggering SQL statement, therefore, overriding the actions of the triggering statements. INSTEAD OF cannot be specified for DDL or logon triggers.
04:00

9

สิ่งนี้ใช้ได้กับ MySQL และเป็นเพียงธุรกรรมโดยปริยาย แต่ควรเป็นดังนี้:

UPDATE Table1 t1, Table2 t2 SET 
t2.field = t2.field+2,
t1.field = t1.field+2

WHERE t1.id = t2.foreign_id and t2.id = '123414'

หากคุณกำลังทำการอัปเดตไปยังหลายตารางที่ต้องมีหลายคำสั่ง ... ซึ่งเป็นไปได้ถ้าคุณอัปเดตอีกอันจากนั้นก็เป็นไปตามเงื่อนไขอื่น ๆ ... คุณควรใช้ธุรกรรม 


1
Anser นี้ยังเกี่ยวข้องกับผู้ใช้รายอื่น
Kyselejsyreček

1
@ Kyselejsyrečekคำตอบนี้ควรหลีกเลี่ยงค่าใช้จ่ายทั้งหมด MySQL มีนิสัยและกลิ่นที่พอเพียงซึ่งส่วนใหญ่ไม่ได้รับการสนับสนุน แต่ถูกเก็บไว้เพื่อหลีกเลี่ยงการทำลายรหัสที่ขึ้นอยู่กับนิสัยใจคอเหล่านั้น การอัปเกรดสามารถทำลายพวกเขาได้อย่างง่ายดายหรือส่งผลให้เกิดพฤติกรรมที่ไม่คาดคิดและปัญหาด้านประสิทธิภาพ
Panagiotis Kanavos



0

จากมุมมองของฉันคุณสามารถทำได้การอัพเดตแบบหนึ่งต่อหนึ่งของสองตารางใน SQL Server:

 BEGIN TRANSACTION

      DECLARE @CNSREQ VARCHAR(30)
      DECLARE @ID INT
      DECLARE @CNSRQDT VARCHAR(30)
      DECLARE @ID2 INT

      DECLARE @IDCNSREQ INT
      DECLARE @FINALCNSREQ VARCHAR(30)
      DECLARE @FINALCNSRQDT VARCHAR(30)
      DECLARE @IDCNSRQDT INT


      SET @CNSREQ=(SELECT MIN(REQUISICIONESDT.CNSREQ) FROM REQUISICIONESDT
          INNER JOIN 
              REQUISICIONES
                ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
           AND REQUISICIONES.CNSREQ = REQUISICIONESDT.CNSREQ AND REQUISICIONESDT.IDREQ = REQUISICIONES.ID
        WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID)

      SELECT REQUISICIONES.CNSREQ, REQUISICIONES.ID, REQUISICIONES.CNSRQDT FROM REQUISICIONES
       INNER JOIN 
          REQUISICIONESDT
              ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
               AND REQUISICIONES.CNSREQ = REQUISICIONESDT.CNSREQ AND REQUISICIONESDT.IDREQ = REQUISICIONES.ID
        WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
    AND REQUISICIONES.CNSREQ = @CNSREQ

        UPDATE REQUISICIONESDT SET  REQUISICIONESDT.CNSREQ=NULL, REQUISICIONESDT.IDREQ=NULL
          FROM REQUISICIONES INNER JOIN REQUISICIONESDT
             ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
       WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
      AND REQUISICIONES.CNSREQ = @CNSREQ

        UPDATE REQUISICIONES SET REQUISICIONES.CNSRQDT=NULL, REQUISICIONES.IDRQDT=NULL
          FROM REQUISICIONES INNER JOIN REQUISICIONESDT
          ON REQUISICIONESDT.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
       WHERE REQUISICIONES.CNSRQDT = REQUISICIONES.CNSRQDT AND REQUISICIONES.IDRQDT = REQUISICIONESDT.ID
     AND REQUISICIONES.CNSREQ = @CNSREQ

       SET @ID2=(SELECT MIN(REQUISICIONESDT.ID) FROM REQUISICIONESDT
        WHERE ISNULL(REQUISICIONESDT.IDREQ,0)<>0)
     DELETE FROM REQUISICIONESDT WHERE REQUISICIONESDT.ID=@ID2


      SET @IDCNSREQ=(SELECT MIN (REQUISICIONES.ID)FROM REQUISICIONES
          INNER JOIN REQUISICIONESDT ON
        REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
         WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)

        SET @FINALCNSREQ=(SELECT MIN (REQUISICIONES.CNSREQ)FROM REQUISICIONES
            INNER JOIN REQUISICIONESDT ON
        REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
         WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)

         SET @FINALCNSRQDT=(SELECT MIN(REQUISICIONESDT.CNSRQDT) FROM REQUISICIONES
           INNER JOIN REQUISICIONESDT ON
          REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
           WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)

          SET @IDCNSRQDT=(SELECT MIN (REQUISICIONESDT.ID)FROM REQUISICIONES
           INNER JOIN REQUISICIONESDT ON
         REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD  
         WHERE REQUISICIONES.CNSRQDT IS NULL AND REQUISICIONES.IDRQDT IS NULL)

           UPDATE REQUISICIONES SET REQUISICIONES.CNSRQDT = @FINALCNSRQDT, REQUISICIONES.IDRQDT=@IDCNSRQDT FROM REQUISICIONES
            INNER JOIN REQUISICIONESDT ON
             REQUISICIONESDT.CEDULA = REQUISICIONES.CEDULA AND REQUISICIONES.FECHA_SOLICITUD = REQUISICIONESDT.FECHA_SOLICITUD
            WHERE REQUISICIONESDT.CNSRQDT = @FINALCNSRQDT AND REQUISICIONESDT.ID = @IDCNSRQDT 


ROLLBACK TRANSACTION

-2

มันง่ายเหมือนแบบสอบถามนี้ที่แสดงด้านล่าง

UPDATE 
  Table1 T1 join Table2 T2 on T1.id = T2.id
SET 
  T1.LastName='DR. XXXXXX', 
  T2.WAprrs='start,stop'
WHERE 
  T1.id = '010008'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.