2009-04-30 28 views
63

Làm cách nào để lưu trữ giá trị trường đã chọn vào một biến từ một truy vấn và sử dụng nó trong một câu lệnh cập nhật?Làm cách nào để gán kết quả được chọn cho một biến?

Dưới đây là thủ tục của tôi:

Tôi đang viết một SQL Server 2005 T-SQL stored procedure mà thực hiện như sau:

  1. được danh sách các hoá đơn id từ bảng hóa đơn và các cửa hàng để con trỏ
  2. Tìm nạp id hóa đơn từ con trỏ - biến tmp_key
  3. foreach tmp_key tìm id liên hệ chính của khách hàng hóa đơn từ bảng khách hàng
  4. cập nhật liên hệ khách hàng quan trọng với id liên lạc chính
  5. con trỏ gần

Dưới đây là mã của tôi:

DECLARE @tmp_key int 
DECLARE @get_invckey cursor 

set @get_invckey = CURSOR FOR 
    select invckey from tarinvoice where confirmtocntctkey is null and tranno like '%115876' 

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey into @tmp_key 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT c.PrimaryCntctKey as PrimaryContactKey 
    from tarcustomer c, tarinvoice i 
    where i.custkey = c.custkey and i.invckey = @tmp_key 

    UPDATE tarinvoice set confirmtocntctkey = PrimaryContactKey where invckey = @tmp_key 
    FETCH NEXT FROM @get_invckey INTO @tmp_key 
END 

CLOSE @get_invckey 
DEALLOCATE @get_invckey 

Làm thế nào để lưu trữ các PrimaryContactKey và sử dụng nó một lần nữa trong tập khoản của báo cáo cập nhật sau đây? Tôi có tạo biến con trỏ hay chỉ một biến cục bộ khác có loại int không?

+2

Như @GilaMonster câu trả lời dưới đây, toàn bộ hoạt động này có thể là một tuyên bố đơn CẬP NHẬT (gọi là "hoạt động thiết lập dựa trên", không nên nhầm lẫn với một [câu lệnh SET t-sql] (https : //msdn.microsoft.com/en-us/library/ms189484.aspx)) là cách tiếp cận tốt hơn nhiều (thực thi nhanh hơn, ít chi phí hơn và ít mã hơn đáng kể). Tôi chỉ chỉ ra điều này vì câu hỏi và tất cả các câu trả lời hàng đầu hiện tại là về cách viết một câu lệnh SET, nhưng nó thực sự không phải là cách tiếp cận tốt nhất để bắt đầu. – gregmac

Trả lời

40
DECLARE @tmp_key int 
DECLARE @get_invckey cursor 

SET @get_invckey = CURSOR FOR 
    SELECT invckey FROM tarinvoice WHERE confirmtocntctkey IS NULL AND tranno LIKE '%115876' 

OPEN @get_invckey 

FETCH NEXT FROM @get_invckey INTO @tmp_key 

DECLARE @PrimaryContactKey int --or whatever datatype it is 

WHILE (@@FETCH_STATUS = 0) 
BEGIN 
    SELECT @PrimaryContactKey=c.PrimaryCntctKey 
    FROM tarcustomer c, tarinvoice i 
    WHERE i.custkey = c.custkey AND i.invckey = @tmp_key 

    UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey WHERE invckey = @tmp_key 
    FETCH NEXT FROM @get_invckey INTO @tmp_key 
END 

CLOSE @get_invckey 
DEALLOCATE @get_invckey 

EDIT:
Câu hỏi này đã nhận được rất nhiều lực kéo hơn tôi đã có dự đoán. Lưu ý rằng tôi không ủng hộ việc sử dụng con trỏ trong câu trả lời của tôi, mà là hiển thị cách gán giá trị dựa trên câu hỏi.

18

Hãy thử này

SELECT @PrimaryContactKey = c.PrimaryCntctKey 
FROM tarcustomer c, tarinvoice i 
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key 

UPDATE tarinvoice SET confirmtocntctkey = @PrimaryContactKey 
WHERE invckey = @tmp_key 
FETCH NEXT FROM @get_invckey INTO @tmp_key 

Bạn sẽ khai báo biến này bên ngoài vòng lặp của bạn như chỉ là một biến TSQL chuẩn.

Tôi cũng nên lưu ý rằng đây là cách bạn sẽ làm điều đó cho bất kỳ loại lựa chọn nào thành một biến, không chỉ khi giao dịch với con trỏ.

13

Tại sao bạn cần con trỏ? Toàn bộ đoạn mã của bạn có thể được thay thế bằng mã này, sẽ chạy nhanh hơn rất nhiều trên nhiều hàng.

UPDATE tarinvoice set confirmtocntctkey = PrimaryCntctKey 
FROM tarinvoice INNER JOIN tarcustomer ON tarinvoice.custkey = tarcustomer.custkey 
WHERE confirmtocntctkey is null and tranno like '%115876' 
+0

Con trỏ có thực sự cau mày không? – phill

+4

Chúng chậm. SQL Server được tối ưu hóa cho các truy vấn dựa trên tập hợp. Nó nhanh hơn để nó hoạt động trên một triệu hàng trong một truy vấn hơn là hoạt động trên một hàng một triệu lần. Thêm vào đó chi phí mà con trỏ có, và bạn đang yêu cầu các vấn đề hiệu suất lớn bằng cách sử dụng con trỏ thay vì các hoạt động dựa trên thiết lập Kiểm tra giải pháp con trỏ và truy vấn của tôi, xem thời gian thực hiện của hai con trỏ là gì. – GilaMonster

+0

Cảm ơn người đàn ông !!!! Điều này đã làm cho tôi, cũng dễ dàng hơn làm việc ra làm thế nào để thay đổi con trỏ cho kịch bản cụ thể của tôi. Bạn là một nhà vô địch! –

81

Tôi chỉ có cùng một vấn đề và ...

declare @userId uniqueidentifier 
set @userId = (select top 1 UserId from aspnet_Users) 

hoặc thậm chí ngắn hơn:

declare @userId uniqueidentifier 
SELECT TOP 1 @userId = UserId FROM aspnet_Users 
+1

Haha, tôi thích điều này. nên rất đơn giản để gán giá trị vô hướng. Hate cursors bla3 .. May mắn googling tìm thấy câu trả lời này ít. – CallMeLaNN

+3

Tôi không biết vì 'set @userId = (chọn top 1 UserId từ aspnet_Users)' ** không có khung ** sẽ dẫn đến "cú pháp sai gần chọn"! – CallMeLaNN

+0

Diễn đàn này cho thấy cách tiếp cận phù hợp cho đầu trang: http://www.sqlservercentral.com/Forums/Topic496124-169-1.aspx –

9

Để gán một biến một cách an toàn, bạn phải sử dụng SET-CHỌN tuyên bố:

SET @PrimaryContactKey = (SELECT c.PrimaryCntctKey 
    FROM tarcustomer c, tarinvoice i 
    WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key) 

Đảm bảo bạn ha đã bắt đầu và dấu ngoặc đơn kết thúc!

Lý do phiên bản SET-SELECT là cách an toàn nhất để đặt biến là gấp hai lần.

1.SELECT trả về một số bài đăng

Điều gì sẽ xảy ra nếu kết quả sau đây chọn trong một số bài đăng?

SELECT @PrimaryContactKey = c.PrimaryCntctKey 
FROM tarcustomer c, tarinvoice i 
WHERE i.custkey = c.custkey 
    AND i.invckey = @tmp_key 

@PrimaryContactKey sẽ được gán giá trị từ bài cuối cùng trong kết quả.

Thực tế, @PrimaryContactKey sẽ được chỉ định một giá trị cho mỗi bài trong kết quả, do đó, do đó nó sẽ chứa giá trị của bài đăng cuối cùng mà lệnh SELECT đang xử lý.

Bài đăng "cuối cùng" được xác định bởi bất kỳ chỉ mục nhóm nào hoặc nếu không có chỉ mục nhóm được sử dụng hoặc khóa chính được nhóm lại, bài đăng "cuối cùng" sẽ là bài đăng được thêm gần đây nhất. Hành vi này có thể, trong trường hợp xấu nhất, được thay đổi mỗi lần lập chỉ mục của bảng được thay đổi.

Với câu lệnh SET-SELECT, biến của bạn sẽ được đặt thành null.

2. SELECT trả về không có bài

gì sẽ xảy ra, khi sử dụng phiên bản thứ hai của mã, nếu bạn chọn không trả lại kết quả một chút nào?

Ngược lại với những gì bạn có thể tin rằng giá trị của biến sẽ không bị rỗng - số này sẽ giữ lại giá trị trước đó của nó!

Điều này là do, như đã nêu ở trên, SQL sẽ chỉ định giá trị cho biến một lần cho mỗi bài đăng - có nghĩa là nó sẽ không làm bất cứ điều gì với biến nếu kết quả không chứa bài đăng. Vì vậy, biến sẽ vẫn có giá trị mà nó có trước khi bạn chạy câu lệnh.

Với tuyên bố SET-SELECT giá trị sẽ là null.

Xem thêm: SET versus SELECT when assigning variables?

+0

Erk là chính xác và điều này phải được đánh dấu là câu trả lời. Điểm thứ hai là điều bắt gặp tôi gần đây ... – wexman

+0

@wexman: tại sao, cảm ơn bạn! Tôi cũng đã có các lần chạy với số 2 ... – Erk

+0

Tôi vừa giải quyết một lỗi với mã sau trường hợp 1 ở trên. Các coder ban đầu dường như không quan tâm rằng một số hàng đã được chọn, nhưng tiếc là một MS SQL Server đôi khi có thể trả lại các hàng theo thứ tự khác hơn so với chúng được chèn vào vì không có lý do rõ ràng hơn tối ưu hóa ... kết quả là ngẫu nhiên và khó hiểu ... – Erk

Các vấn đề liên quan