Cập nhật truy vấn bằng Truy vấn con trong Sql Server


83

Tôi có một cấu trúc bảng đơn giản như thế này:

Bảng tempData

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║    80 ║
║ Ravi     ║    85 ║
║ Sanjay   ║    90 ║
╚══════════╩═══════╝

Và tôi cũng có một tên bảng khác là tempDataView như thế này

╔══════════╦═══════╗
║   NAME   ║ MARKS ║
╠══════════╬═══════╣
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Narendra ║       ║
║ Ravi     ║       ║
║ Ravi     ║       ║
║ Sanjay   ║       ║
╚══════════╩═══════╝

Tôi muốn cập nhật bảng tempDataView , bằng cách đặt Marks theo tempDataView - Tên so với tempData - Tên

Vâng, hãy để tôi chỉ cho bạn những gì tôi đã thử, tôi đã cố gắng giải quyết vấn đề này bằng cách sử dụng Con trỏ và nó đã được giải quyết hoàn hảo, nhưng tôi đang tìm cách giải quyết bằng cách sử dụng Truy vấn con

Nó đây:

Declare @name varchar(50),@marks varchar(50)
Declare @cursorInsert CURSOR
set @cursorInsert = CURSOR FOR
Select name,marks from tempData
OPEN @cursorInsert
FETCH NEXT FROM @cursorInsert
into @name,@marks
WHILE @@FETCH_STATUS = 0
BEGIN
UPDATE tempDataView set marks = @marks where name = @name
FETCH NEXT FROM @cursorInsert
INTO @name,@marks
END
CLOSE @cursorInsert
DEALLOCATE @cursorInsert

Thực ra nó giống như bài tập về nhà để tôi giải nó bằng cách sử dụng Truy vấn con.

Câu trả lời:


180

bạn có thể tham gia cả hai bảng ngay cả trên các UPDATEcâu lệnh,

UPDATE  a
SET     a.marks = b.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

để có hiệu suất nhanh hơn, hãy xác định INDEXcột markstrên cả hai bảng.

sử dụng SUBQUERY

UPDATE  tempDataView 
SET     marks = 
        (
          SELECT marks 
          FROM tempData b 
          WHERE tempDataView.Name = b.Name
        )

1
Đúng rồi. nhưng hãy gợi ý cho tôi bất kỳ cách nào để thực hiện việc này bằng cách sử dụng truy vấn con.
Narendra Pal,

1
cập nhật câu trả lời với subquery, nhưng tôi khá sử dụng JOINhơn SUBQUERY.
John Woo,

1
Tại sao người ta phải xác định một INDEXtrên các markscột? Nó không có trên các Namecột?
lindelof

1
Gặp lỗi: Truy vấn con trả về nhiều hơn 1 giá trị. Điều này không được phép khi truy vấn con theo sau =,! =, <, <=,>,> = Hoặc khi truy vấn con được sử dụng như một biểu thức.
Pradip

1
Hãy tự thử truy vấn con và điều chỉnh nó cho đến khi bạn chỉ nhận được 1 kết quả. Có thể đổi SELECTthànhSELECT TOP 1
vahanpwns

33

bởi vì bạn chỉ mới học, tôi khuyên bạn nên thực hành chuyển đổi các phép nối CHỌN thành các phép nối CẬP NHẬT hoặc XÓA. Đầu tiên, tôi khuyên bạn nên tạo một câu lệnh SELECT kết hợp hai bảng này:

SELECT *
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Sau đó, lưu ý rằng chúng ta có hai bí danh bảng ab. Sử dụng các bí danh này, bạn có thể dễ dàng tạo câu lệnh UPDATE để cập nhật bảng a hoặc b. Đối với bảng a, bạn có câu trả lời do JW cung cấp. Nếu bạn muốn cập nhật b, câu lệnh sẽ là:

UPDATE  b
SET     b.marks = a.marks
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Bây giờ, để chuyển câu lệnh thành câu lệnh DELETE, hãy sử dụng cách tiếp cận tương tự. Câu lệnh dưới đây sẽ chỉ xóa khỏi a(giữ nguyên b) đối với những bản ghi khớp theo tên:

DELETE a
FROM    tempDataView a
        INNER JOIN tempData b
            ON a.Name = b.Name

Bạn có thể sử dụng SQL Fiddle do JW tạo ra làm sân chơi


5
cách học đúng đắn của nó. 1 cho thấy cách để study.thanks
Narendra Pal

3

Ở đây trong mẫu của tôi, tôi tìm ra giải pháp của điều này, bởi vì tôi đã gặp vấn đề tương tự với các bản cập nhật và truy vấn con:

UPDATE
    A
SET
    A.ValueToChange = B.NewValue
FROM
    (
        Select * From C
    ) B
Where 
    A.Id = B.Id

1
Cảm ơn bạn vì câu trả lời này! Để giúp những người khác đọc được điều này, bạn có thể nhanh chóng thêm giải thích tại sao mã này giải quyết được vấn đề không?
RedBassett

0

Tiêu đề của chủ đề này hỏi cách truy vấn con có thể được sử dụng trong bản cập nhật. Đây là một ví dụ về điều đó:

update [dbName].[dbo].[MyTable] 
set MyColumn = 1 
where 
    (
        select count(*) 
        from [dbName].[dbo].[MyTable] mt2 
        where
            mt2.ID > [dbName].[dbo].[MyTable].ID
            and mt2.Category = [dbName].[dbo].[MyTable].Category
    ) > 0

Tôi không chắc điều này thậm chí sẽ được biên dịch như thế nào, không có nhóm nào cho số đếm (*) để biết những gì cần đếm.
crthompson, 31-07-18

@paqogomez chỉ cần thử nó - trên bất kỳ bảng nào có bất kỳ bản ghi nào trong đó. ví dụ. select count (*) from EventLog where year = 2018
Graham Laight

Vì vậy, sau đó bạn chỉ đơn giản là đếm toàn bộ bảng. Tôi đứng bằng cách bỏ phiếu xuống của tôi, điều này không có gì để làm với các câu hỏi (không phụ thuộc vào tiêu đề)
crthompson

Đó là đặc quyền của bạn, nhưng tiêu đề của chuỗi này là "cập nhật truy vấn bằng cách sử dụng truy vấn con" và ví dụ của tôi hiển nhiên làm chính xác điều đó. fyi Tôi không đếm "toàn bộ bảng" - count (*) được theo sau bởi mệnh đề "where" - vì vậy nó đang đếm các hàng đáp ứng điều kiện "where".
Graham Laight

0

Dưới đây là một lời giải thích hay về hoạt động cập nhật với một số ví dụ. Mặc dù đó là trang Postgres, nhưng các truy vấn SQL cũng hợp lệ cho các DB khác. Các ví dụ sau đây là trực quan để hiểu.

-- Update contact names in an accounts table to match the currently assigned salesmen:

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

-- A similar result could be accomplished with a join:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

Tuy nhiên, truy vấn thứ hai có thể cho kết quả không mong muốn nếu salesmen.id không phải là khóa duy nhất, trong khi truy vấn đầu tiên được đảm bảo sẽ phát sinh lỗi nếu có nhiều id trùng khớp. Ngoài ra, nếu không có kết quả phù hợp cho một mục nhập account.sales_id cụ thể, truy vấn đầu tiên sẽ đặt các trường tên tương ứng thành NULL, trong khi truy vấn thứ hai sẽ không cập nhật hàng đó.

Do đó đối với ví dụ đã cho, truy vấn đáng tin cậy nhất giống như sau.

UPDATE tempDataView SET (marks) =
    (SELECT marks FROM tempData
     WHERE tempDataView.Name = tempData.Name);

Thật không may, biểu mẫu đầu tiên không hoạt động trong máy chủ MS SQL.
AntoineL
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.