Các toán tử tương tự 'in' so sánh hai bộ


7

Tôi muốn so sánh hai bộ giá trị và xem liệu có giao điểm không. Bộ giá trị đầu tiên được chỉ định trong thời gian chạy và bộ giá trị thứ hai được lưu trữ trong một hàng của cơ sở dữ liệu.

Dưới đây là một số mã mẫu:

CREATE TABLE #tab1 (var1 INT, var2 INT , var3 INT)

INSERT INTO #tab1 
VALUES (1,2,3),(0,0,0),(0,4,0)

Select
a = (case when 1 IN (var1,var2,var3) OR
               2 IN (var1,var2,var3) OR
               3 IN (var1,var2,var3)
    THEN 1 else 0 end) 
from #tab1

Tôi cảm thấy rằng mã quá rườm rà, và tự hỏi liệu có một số cách đơn giản để làm điều đó. Cảm ơn!


1
Bạn có muốn so sánh hai bộ giá trị (có nghĩa là hai bộ hàng trong một bảng) hoặc hai bộ biến (một số lượng giới hạn của chúng) và xem giá trị nào giống nhau không? Mã của bạn ngụ ý 3 biến và bộ thứ hai là 1,2,3, phải không? Bạn có thể cho ví dụ về hai bộ? Xin cho một ví dụ tích cực và tiêu cực.
Grimaldi

@Grimaldi, cảm ơn bạn đã nhắc nhở và tôi đã cập nhật câu hỏi. Xin vui lòng xem và xem bây giờ nó rõ ràng.
Jason

Câu hỏi bây giờ là so sánh 3 cột với 3 giá trị thời gian chạy và báo cáo bất kỳ một cột nào khớp. Điều này sẽ được "đơn giản hóa" bằng cách chuyển đổi bảng thành 1 cột giá trị, bạn có thể thực hiện với "Khóa CHỌN, var1 TỪ # tab1 Phím UNION ALL CHỌN, var2 ... Khóa UNION ALL SELECT, var3", nhưng tôi Đừng nghĩ rằng nó tốt hơn mã của bạn hoặc sẽ chạy nhanh hơn. Bạn có thể đặt nó trong một cái nhìn. Công thức của bạn xuất 1 trên mỗi hàng chứa 1 hoặc nhiều đầu vào thời gian chạy, mà tôi đoán là bạn muốn lấy gì, hoặc nếu không, bạn muốn chọn các hàng có a = 1 trong ví dụ, làm tập hợp kết quả?
Robert Carnegie

Các câu hỏi về ví dụ sửa đổi của bạn: bạn có thực sự cần trả về tất cả các hàng (với giá trị thật / sai) hay bạn thực sự chỉ quan tâm đến việc trả về các hàng trong đó bất kỳ 3 cột nào khớp với 3 giá trị khác của bạn? Có các cột có liên quan khác mà bạn cần phải trả lại, như một ID nào đó không?
BradC

@BradC, cảm ơn sự giúp đỡ của bạn! Tôi cần tất cả các hàng được trả lại. Có những hàng khác tôi muốn trả lại cùng với các hàng đúng / sai. Nó có thay đổi các câu hỏi không?
Jason

Câu trả lời:


1

Cho ba đầu vào được thiết lập và một giá trị bảng riêng biệt, mã sau đây sẽ hoạt động.

declare @input1 int =1
declare @input2 int =2
declare @input3 int =3

CREATE TABLE #tab1 (var1 INT, var2 INT , var3 INT)
INSERT INTO #tab1 
VALUES (1,2,3),(0,0,0),(0,4,0),(1,4,1),(4,0,0),(0,5,1),(2,4,0),(1,4,3)


 declare @set table(input int)
 insert  @set values (@input1), (@input2),(@input3);

 select distinct #tab1.*, case when join1.i1 is null then 'No Match' else 'match' end matching
 from #tab1
 left join (select distinct a.input i1, b.input i2 ,c.input i3
                from @set a 
                cross join @set b 
                cross join @set c ) join1
    on join1.i1=#tab1.var1
        or join1.i2=#tab1.var2
        or join1.i3=#tab1.var3

Tôi nghĩ rằng đây là những gì bạn đang tìm kiếm nếu bạn không muốn sử dụng 'in'. Thành thật mà nói, tôi sẽ sử dụng 'trong'. Nó đơn giản hơn nhiều và dễ viết hơn. Các mã trên mất một thời gian để làm việc. Tuy nhiên, tôi sẽ cập nhật mã 'in' của bạn như sau:

select * ,'match'
from #tab1
where @input1 in (var1, var2, var3)
    or @input2 in (var1, var2, var3)
    or @input3 in (var1, var2, var3)
union 
select * ,'no-match'
from #tab1
where @input1 not in (var1, var2, var3)
    and @input2 not in (var1, var2, var3)
    and @input3 not in (var1, var2, var3)

Cảm ơn bạn đã giúp đỡ! Khi tôi đăng câu hỏi này, tôi nghĩ sẽ có một chức năng phổ quát để giải quyết loại câu hỏi như vậy. Nhưng hóa ra không có giải pháp nào như vậy rõ ràng ....
Jason

10

Bạn chỉ có thể JOINvào các bảng có nguồn gốc thực hoặc động:

DECLARE @var1 INT=2;
DECLARE @var2 INT=15;
DECLARE @var3 INT=-7;

IF EXISTS (SELECT 1 FROM 
             (VALUES (1),(2),(3))tableNums(number)
             INNER JOIN (VALUES (@var1), (@var2), (@var3))tableVars(var)
             ON tableNums.number=tableVars.var
       )
    SELECT 1    --or do something else interesting
ELSE SELECT 0   --or do the opposite

Nếu danh sách rất dài, có lẽ tôi sẽ tạo nó trong bảng #temp trước thay vì thực hiện nó trong câu lệnh, nhưng logic JOINEXISTSlogic sẽ giống nhau.


Tương tự, chúng ta có thể sử dụng INTERSECTthay vì JOIN:

CASE WHEN EXISTS ( SELECT * FROM (VALUES (1), (2), (3)) AS x(i) 
                 INTERSECT 
                   SELECT * FROM (VALUES (@var1), (@var2), (@var3)) AS y(i)
                 )
THEN 1 ELSE 0 END 

Kiểm tra tại dbfiddle.uk .


Xin lỗi, câu hỏi của tôi không rõ ràng ngay từ đầu. Các biến tôi đã đề cập thực sự là các cột trong cơ sở dữ liệu. Vì vậy, câu trả lời của bạn không thể giải quyết câu hỏi của tôi trực tiếp. Bạn có thể xem câu hỏi cập nhật? Cảm ơn!
Jason

1
Câu trả lời hoạt động tốt với các biến hoặc cột. Bạn đã thử à?
ypercubeᵀᴹ

4

Bạn có thể thử cách sau thay vì CASE

declare @var1 int, @var2 int, @var3 int

set @var1 = 1
set @var2 = 2
Set @var3 = 3

IF 1 IN (@var1, @var2, @var3) or 2 in (@var1, @var2, @var3) or 3 in (@var1, @var2, @var3)
BEGIN
    Select 1;
END

else 
BEGIN
    select 0;
END

Xin lỗi, câu hỏi của tôi không rõ ràng ngay từ đầu. Các biến tôi đã đề cập thực sự là các cột trong cơ sở dữ liệu. Bạn có thể xem câu hỏi cập nhật? Cảm ơn!
Jason

1

Nếu bạn không cần giữ các biến, thì bạn có thể viết một vòng lặp như,

SET @found = 0
WHILE @var1 IS NOT NULL AND @found = 0
BEGIN
  IF @var1 IN (1, 2, 3) 
  BEGIN SET @found = 1  END
  ELSE
  BEGIN
    SET @var1 = @var2; SET @var2 = @var3; SET @var3 = NULL
  END
END

... nhưng đó không phải là bàn. Chúng tôi là DBA và chúng tôi sử dụng bảng.


Cảm ơn sự giúp đỡ của bạn và tôi đã cập nhật câu hỏi. Bạn có thể xem nó?
Jason
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.