Thoát một truy vấn trong một tuyên bố trường hợp?


8

Tôi đang cố gắng thiết lập một truy vấn, để nó sẽ so sánh hai ngày từ hai bảng khác nhau và nếu chúng bằng nhau, thì truy vấn sẽ thoát. Nếu chúng không bằng nhau, thì truy vấn sẽ tiếp tục và chèn một số thứ. Tuy nhiên, tôi không thể tìm ra cách để làm cho nó làm những gì tôi muốn.

SELECT TOP(1) @dateA=a.someDate
FROM a
ORDER BY DESC;
SELECT TOP(1) @dateB=b.someDate
FROM b
ORDER BY DESC;

CASE WHEN @dateA=@dateB THEN raiseerror('dates equal',20,-1) with log;

Insert statements;

Bất kỳ trợ giúp sẽ được siêu đánh giá cao.


Một số biến thể khác của SQL có cả biểu thức và câu lệnh có tên CASE- SQL Server chỉ có CASEbiểu thức.
RDFozz

3
Bạn có thực sự muốn nâng cao lỗi? Hay đó chỉ là một nỗ lực thoát ra?
Kevin

Câu trả lời:


16

CASE là một biểu thức (không phải là câu lệnh) và không thể được sử dụng cho điều khiển luồng như thế - không gọi lệnh, không trả về nhiều hơn một cột / giá trị, không được sử dụng làm lệnh riêng.

Dường như với tôi, bạn chỉ có thể sử dụng IFđể tăng lỗi khi ngày bằng nhau, nếu không thì chạy các phần chèn.

IF @dateA = @dateB 
BEGIN
  raiseerror('dates equal',20,-1) with log;
END
ELSE -- maybe you don't need a batch-aborting, logging error level
BEGIN
  INSERT ...
END

Bạn cũng có thể làm theo cách khác. Chỉ chạy các phần chèn nếu ngày không bằng nhau , nếu không sẽ tăng lỗi:

IF @dateA <> @dateB
BEGIN
  INSERT ...
END
ELSE
BEGIN
  raiserror ...
END

Nếu bạn nghĩ rằng để sử dụng các lỗi chỉ nhằm mục đích nhận được ra khỏi chạy chèn, sau đó bạn chỉ có thể loại bỏ tất cả mọi thứ từ ELSExuống, vì cách duy nhất chèn sẽ chạy là khi @dateA@dateBkhông bằng nhau :

IF @dateA <> @dateB
BEGIN
  INSERT ...
END

Tôi đã thu nhỏ lại cách trở thành mô phạm về những thứ như hàng (so với "bản ghi") và cột (so với "trường"), nhưng toàn bộ biểu thức so với điều tuyên bố là một sự khác biệt rất quan trọng, vì chính xác lý do này. Xem " Bí mật bẩn thỉu của biểu hiện CASE ."


Chủ yếu là một câu trả lời tốt, ngoại trừ một nitpick .. Sử dụng toán tử '<>' không chơi tốt với các giá trị NULL. Nếu một trong các giá trị ngày của bạn là NULL, toán tử 'không bằng' sẽ trả về kết quả không mong muốn. Hãy thử "CHỌN TRƯỜNG HỢP KHI (1 <> NULL) THEN '! =' ELSE '==' END"
user5151179

1
@ user5151179 Tôi khá chắc chắn Aaron biết sự khác biệt. Đồng thời kiểm tra xem OP trong câu hỏi cho biết anh ta muốn làm gì khi hai ngày bằng nhau và khi nào không bằng nhau. Anh ta không đề cập đến tất cả những gì họ muốn làm khi một hoặc cả hai NULL. Đây vẫn là một nhận xét tốt rằng hai phiên bản mà Aaron cung cấp sẽ làm những việc khác nhau trong trường hợp đó.
ypercubeᵀᴹ

6

Sử dụng IFthay vì mộtCASE

 IF @dateA=@dateB 
    raiseerror('dates equal',20,-1) with log;
 ELSE
    BEGIN
        Insert statements;
    END

Điều này tất nhiên giả định rằng bạn thực sự muốn đưa ra một lỗi. Tùy chọn khác sẽ là:

 IF @dateA<>@dateB 
    BEGIN
        Insert statements;
    END

Bây giờ, lưu ý BEGINEND. Những điều đó sẽ trở nên quan trọng. những IFtuyên bố (và ELSE) chỉ ảnh hưởng đến lệnh ngay dưới nó. Nếu bạn cần nhiều hơn một lệnh, bạn cần BEGIN và END .


2

Các câu trả lời khác đã chỉ ra rằng CASE là một biểu thức , không phải là một câu lệnh và do đó, bản thân nó không thể bao gồm các câu lệnh (như RAISEERRORhoặc bất kỳ câu nào khác). Nếu các điều kiện không nhiều - đặc biệt khi đó chỉ là một điều kiện, - câu lệnh IF là lựa chọn hoàn hảo cho những gì bạn đang cố gắng thực hiện, như đã được đề cập.

Tuy nhiên, tùy thuộc vào kịch bản của bạn, một biểu thức CASE vẫn có thể được sử dụng, chỉ không chính xác như cách bạn đã thể hiện. Cụ thể, nếu có nhiều điều kiện cần kiểm tra trong đó một trận đấu sẽ dẫn đến cùng một tập hợp hành động (ví dụ: đưa ra một ngoại lệ và chấm dứt tập lệnh), bạn có thể sử dụng biểu thức CASE trong câu lệnh gán lưu trữ kết quả của CASE, sau đó làm theo nó với IF kiểm tra kết quả được lưu trữ và thực hiện (các) hành động cần thiết nếu thích hợp, như thế này:

DECLARE @ErrorMessage varchar(1000);

SET @ErrorMessage =
  CASE WHEN @dateA = @dateB THEN
    'Dates equal'
  CASE WHEN ... /* some other condition */ THEN
    'Some other message'
  .
  .
  .
  ELSE
    ''  -- no message if nothing is wrong;
        -- you can also omit the ELSE branch entirely,
        -- which means the same as ELSE NULL
  END
;

IF @ErrorMessage <> ''
BEGIN
  RAISERROR (@ErrorMessage, 20, -1) WITH LOG;
END;

... /* continue the script */

Trong trường hợp này, hành động cần thiết là đưa ra một ngoại lệ, nhưng thông báo được trả lại với ngoại lệ cần phụ thuộc vào điều kiện nào được kiểm tra trước. Câu lệnh gán sử dụng biểu thức CASE để chọn thông báo nào sẽ lưu trong @ErrorMessagebiến.

Bạn cũng có thể thấy rằng lỗi chỉ được nêu lên một cách có điều kiện - chỉ khi biến thực sự chứa thông báo hiển thị. Nếu giá trị là một chuỗi rỗng hoặc null, tập lệnh sẽ tiếp tục mà không bị gián đoạn.


0

Bạn có cần các biến?

declare @D1 table (dt date);
declare @D2 table (dt date);
insert into @D1 values ('2000-01-01'), ('2000-02-01');
insert into @D2 values ('2000-01-01'), ('2000-02-01');
if (select max(dt) from @D1) = (select max(dt) from @D2)
begin 
   select 'match'
end
else 
begin 
   select 'no match'
end
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.