2009-07-16 34 views
118

tôi cần phải thực hiện các truy vấn sau đây trong SQL Server:SQL WHERE .. tại khoản nhiều cột

select * 
from table1 
WHERE (CM_PLAN_ID,Individual_ID) 
IN 
(
Select CM_PLAN_ID, Individual_ID 
From CRM_VCM_CURRENT_LEAD_STATUS 
Where Lead_Key = :_Lead_Key 
) 

Nhưng mệnh đề WHERE..IN cho phép chỉ có 1 cột. Làm thế nào tôi có thể so sánh 2 hoặc nhiều cột với một SELECT bên trong?

Trả lời

81

Bạn có thể tạo ra một bảng có nguồn gốc từ các subquery, và tham gia table1 bảng có nguồn gốc này:

select * from table1 LEFT JOIN 
(
    Select CM_PLAN_ID, Individual_ID 
    From CRM_VCM_CURRENT_LEAD_STATUS 
    Where Lead_Key = :_Lead_Key 
) table2 
ON 
    table1.CM_PLAN_ID=table2.CM_PLAN_ID 
    AND table1.Individual=table2.Individual 
WHERE table2.CM_PLAN_ID IS NOT NULL 
+5

hoặc thường là SELECT * TỪ bảng INNER THAM GIA các bảng khác ON (bảng.x = otherTable.a AND table.y = otherTable.b) – ala

+3

Còn về nhiều hàng sẽ tồn tại nếu bảng 2 là con của bảng 1? Và tại sao LEFT JOIN? – gbn

+0

@gbn: Cảm ơn, bạn đã đúng. Sửa lỗi đó. – sleske

95

Thay vào đó, bạn sẽ muốn sử dụng cú pháp WHERE EXISTS.

SELECT * 
FROM table1 
WHERE EXISTS (SELECT * 
       FROM table2 
       WHERE Lead_Key = @Lead_Key 
         AND table1.CM_PLAN_ID = table2.CM_PLAN_ID 
         AND table1.Individual_ID = table2.Individual_ID) 
+2

Trong khi điều này có hiệu quả, nó chuyển đổi truy vấn không tương quan trong câu hỏi thành truy vấn tương quan. Trừ khi trình tối ưu hóa truy vấn thông minh, điều này có thể cung cấp cho bạn hiệu suất O (n^2) :-(Nhưng có lẽ tôi đang đánh giá thấp trình tối ưu hóa ... – sleske

+1

Tôi sử dụng các cú pháp như thế này mọi lúc mà không có vấn đề. tối ưu hóa cũ hơn (6.5, 7, 8, v.v.) không nên có vấn đề với cú pháp này – mrdenny

+1

@sleske: EXISTS là tốt hơn nhiều: xem các bình luận của tôi trong câu trả lời của tôi và kiểm tra nó trước, @mrdenny: Tôi hiểu sai câu trả lời của bạn lúc đầu, tôi muốn sử dụng EXISTS quá – gbn

12

Một đơn giản EXISTS khoản là sạch nhất

select * 
from table1 t1 
WHERE 
EXISTS 
(
Select * --or 1. No difference. 
From CRM_VCM_CURRENT_LEAD_STATUS Ex 
Where Lead_Key = :_Lead_Key 
-- correlation here 
AND 
t1.CM_PLAN_ID = Ex.CM_PLAN_ID AND t1.CM_PLAN_ID = Ex.Individual_ID 
) 

Nếu bạn có nhiều hàng trong mối tương quan sau đó một JOIN cho nhiều hàng trong đầu ra, vì vậy bạn cần phân biệt. Mà thường làm cho EXISTS hiệu quả hơn.

Note "SELECT" * với một tham gia cũng sẽ bao gồm các cột từ hàng hạn chế bảng

3

Tại sao sử dụng WHERE EXISTS hoặc có nguồn gốc BẢNG khi bạn chỉ có thể làm một bên bình thường tham gia:

SELECT t.* 
FROM table1 t 
INNER JOIN CRM_VCM_CURRENT_LEAD_STATUS s 
    ON t.CM_PLAN_ID = s.CM_PLAN_ID 
    AND t.Individual_ID = s.Individual_ID 
WHERE s.Lead_Key = :_Lead_Key 

Nếu cặp (CM_PLAN_ID, Individual_ID) không phải là duy nhất trong bảng trạng thái, bạn có thể cần một DISTINCT SELECT *. * thay thế.

+2

Và DISTINCT thường có nghĩa là một EXISTS là hiệu quả hơn – gbn

-3

tôi thành lập dễ dàng hơn theo cách này

Select * 
from table1 
WHERE (convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID)) 
IN 
(
Select convert(VARCHAR,CM_PLAN_ID) + convert(VARCHAR,Individual_ID) 
From CRM_VCM_CURRENT_LEAD_STATUS 
Where Lead_Key = :_Lead_Key 
) 

Hope trợ giúp này :)

+9

Ouch, không có chỉ mục sử dụng ở đây làm cho concat chuỗi. – mrdenny

+9

Tôi đã bình chọn điều này vì nó rất nguy hiểm! Nếu 'CM_PLAN_ID = 45' và' Individual_ID = 3' thì kết quả nối tiếp trong '453' - không thể phân biệt được với trường hợp' CM_PLAN_ID = 4' và 'Individual_ID = 53' ... yêu cầu sự cố tôi có thể nghĩ –

+5

. Tất nhiên bạn có thể nối với một char đặc biệt như '45_3' hoặc' 45: 3' nhưng nó vẫn không phải là một giải pháp * đẹp * và dĩ nhiên là @mrdenny nói rằng các chỉ mục sẽ không được sử dụng ngay bây giờ khi một biến đổi đã diễn ra Các cột. –

-3

Cách đơn giản và sai sẽ được kết hợp hai cột sử dụng + hoặc nối và làm cho một cột.

Select * 
from XX 
where col1+col2 in (Select col1+col2 from YY) 

Điều này có thể sẽ rất chậm. Không thể được sử dụng trong lập trình nhưng nếu trong trường hợp bạn chỉ là truy vấn để xác minh một cái gì đó có thể được sử dụng.

+9

Thật vậy, và nó có thể dẫn đến lỗi, ví dụ: 'ab' + 'c' = 'a' + 'bc' –

1

Nếu bạn muốn cho một bảng sau đó sử dụng sau đây truy vấn

SELECT S.* 
FROM Student_info S 
    INNER JOIN Student_info UT 
    ON S.id = UT.id 
    AND S.studentName = UT.studentName 
where S.id in (1,2) and S.studentName in ('a','b') 

và bảng dữ liệu như sau

id|name|adde|city 
1 a ad ca 
2 b bd bd 
3 a ad ad 
4 b bd bd 
5 c cd cd 

Sau đó, đầu ra như sau

id|name|adde|city 
1 a ad ca 
2 b bd bd 
3
select * from tab1 where (col1,col2) in (select col1,col2 from tab2) 

Lưu ý:
Oracle bỏ qua các hàng có một hoặc nhiều cột được chọn là NULL. Trong những trường hợp này, bạn có thể muốn sử dụng NVL -Funktion để ánh xạ NULL tới một giá trị đặc biệt (không nên có giá trị);

select * from tab1 
where (col1, NVL(col2, '---') in (select col1, NVL(col2, '---') from tab2) 
+0

postgres hỗ trợ 'where (colA, colB) trong (... một số danh sách các bộ dữ liệu ...)' nhưng tôi không chắc cơ sở dữ liệu khác làm gì tương tự. Tôi muốn được biết. –

+2

Cú pháp này cũng được hỗ trợ trong Oracle và DB2/400 (có thể cả DB2). Muốn SQL Server hỗ trợ nó. – CrazyIvan1974

+0

DB2 hỗ trợ điều này. –

0

Chúng ta chỉ cần làm điều này.

select * 
    from 
    table1 t, CRM_VCM_CURRENT_LEAD_STATUS c 
    WHERE t.CM_PLAN_ID = c.CRM_VCM_CURRENT_LEAD_STATUS 
    and t.Individual_ID = c.Individual_ID 
Các vấn đề liên quan