2009-02-12 49 views
37

Tôi là một noob khi nói đến cú pháp SQL.Làm cách nào để kết hợp 2 câu lệnh chọn thành một?

Tôi có một bảng với rất nhiều hàng và cột của khóa học: P phép nói rằng nó trông như thế này:

 AAA BBB CCC DDD 
----------------------- 
Row1 | 1 A D X 
Row2 | 2 B C X 
Row3 | 3 C D Z 

Bây giờ tôi muốn tạo ra một lựa chọn công bố cao cấp mà mang lại cho tôi kết hợp (giả SQLish này đây):

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' 
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' 

Kết quả sẽ là:

Test1, 1, A, D, X 
Test2, 2, B, C, X 

Làm thế nào tôi sẽ kết hợp hai câu lệnh chọn đó vào một câu lệnh chọn lựa tốt đẹp?

Nó có hoạt động nếu tôi phức tạp SQL như dưới đây (vì câu lệnh SQL của riêng tôi chứa một câu lệnh tồn tại)? Tôi chỉ muốn biết làm thế nào tôi có thể kết hợp các lựa chọn và sau đó cố gắng áp dụng nó vào SQL hơi tiên tiến hơn của tôi.

select 'Test1', * from TABLE Where CCC='D' AND DDD='X' AND exists(select ...) 
select 'Test2', * from TABLE Where CCC<>'D' AND DDD='X' AND exists(select ...) 




câu lệnh SQL REAL của tôi là thế này:

select Status, * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 

mà mang lại cho tôi một kết quả. Nhưng tôi muốn kết hợp nó với một bản sao của câu lệnh select này với một AND được thêm vào và trường 'Status' sẽ được thay đổi bằng một chuỗi như 'DELETED'.

select 'DELETED', * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 
+1

+1 đó là câu hỏi cực kỳ được hỏi –

Trả lời

55

. Bạn có hai lựa chọn ở đây. Đầu tiên là để có hai bộ kết quả đó sẽ thiết lập 'Test1' hoặc 'Test2' dựa trên điều kiện trong mệnh đề WHERE, và sau đó UNION chúng lại với nhau:

select 
    'Test1', * 
from 
    TABLE 
Where 
    CCC='D' AND DDD='X' AND exists(select ...) 
UNION 
select 
    'Test2', * 
from 
    TABLE 
Where 
    CCC<>'D' AND DDD='X' AND exists(select ...) 

Điều này có thể là một vấn đề, bởi vì bạn đang đi để quét/tìm kiếm hiệu quả trên BẢNG hai lần.

Các giải pháp khác sẽ được chọn từ bảng một lần, và thiết lập 'Test1' hoặc 'Test2' dựa trên các điều kiện trong TABLE:

select 
    case 
     when CCC='D' AND DDD='X' AND exists(select ...) then 'Test1' 
     when CCC<>'D' AND DDD='X' AND exists(select ...) then 'Test2' 
    end, 
    * 
from 
    TABLE 
Where 
    (CCC='D' AND DDD='X' AND exists(select ...)) or 
    (CCC<>'D' AND DDD='X' AND exists(select ...)) 

Việc nắm bắt ở đây là bạn sẽ phải lặp lại trong các điều kiện lọc trong tuyên bố CASE và tuyên bố WHERE.

+0

Cảm ơn (im sử dụng MS SQL Server 2005). Có vẻ như đây là những gì tôi đang tìm kiếm. UNION quét hai lần, nhưng tôi có thể sống với điều đó. Và tôi không biết rằng câu lệnh CASE có thể được sử dụng một cách tiến bộ. – Wolf5

9

Nếu chúng đến từ cùng một bảng, tôi nghĩ UNION là lệnh bạn đang tìm kiếm.

(Nếu bạn muốn bao giờ cần phải chọn các giá trị từ các cột của các bảng khác nhau, bạn nên nhìn vào JOIN thay ...)

1
select Status, * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 

UNION 

select 'DELETED', * from WorkItems t1 
where exists (select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 

Có lẽ đó sẽ làm các trick. Tôi không thể kiểm tra nó từ đây mặc dù, và tôi không chắc chắn những gì phiên bản của SQL bạn đang làm việc chống lại.

1

sử dụng một trường hợp vào lựa chọn và sử dụng trong các nơi gần HOẶC

một cái gì đó như thế này, tôi đã không kiểm tra nó nhưng nó phải làm việc, tôi nghĩ ...

select case when CCC='D' then 'test1' else 'test2' end, * 
from table 
where (CCC='D' AND DDD='X') or (CCC<>'D' AND DDD='X') 
1

tôi nghĩ đó là những gì bạn đang tìm kiếm:

SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.* 
FROM WorkItems t1 
WHERE (TextField01, TimeStamp) IN(
    SELECT TextField01, MAX(TimeStamp) 
    FROM WorkItems t2 
    GROUP BY t2.TextField01 
) 
AND TimeStamp > '2009-02-12 18:00:00' 

Nếu bạn đang ở Oracle hoặc MS SQL 2005 trở lên, sau đó bạn có thể làm:

SELECT * 
FROM (
    SELECT CASE WHEN BoolField05 = 1 THEN Status ELSE 'DELETED' END AS MyStatus, t1.*, 
    ROW_NUMBER() OVER (PARTITION BY TextField01 ORDER BY TimeStamp DESC) AS rn 
    FROM WorkItems t1 
) to 
WHERE rn = 1 

, nó hiệu quả hơn.

2

Cảm ơn bạn đã nhập. Thử những thứ mà đã được đề cập ở đây và đây là những 2 tôi đã làm việc:

(
select 'OK', * from WorkItems t1 
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND (BoolField05=1) 
) 
UNION 
(
select 'DEL', * from WorkItems t1 
where exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
AND TimeStamp>'2009-02-12 18:00:00' 
AND NOT (BoolField05=1) 
) 

select 
    case 
     when 
      (BoolField05=1) 
    then 'OK' 
    else 'DEL' 
     end, 
     * 
from WorkItems t1 
Where 
      exists(select 1 from workitems t2 where t1.TextField01=t2.TextField01 AND (BoolField05=1)) 
      AND TimeStamp=(select max(t2.TimeStamp) from workitems t2 where t2.TextField01=t1.TextField01) 
      AND TimeStamp>'2009-02-12 18:00:00' 

Đó sẽ là hiệu quả nhất trong số này (chỉnh sửa: thứ hai vì nó chỉ quét bảng một lần), và có thể làm cho nó hiệu quả hơn nữa? (BoolField = 1) thực sự là một biến (dyn sql) có thể chứa bất kỳ câu lệnh nào trên bảng.

Tôi đang chạy trên MS SQL 2005. Đã thử các ví dụ Quassnoi nhưng không hoạt động như mong đợi.

+0

Đây là chất rắn. Cảm ơn :) – Jordon

0
select t1.* from 
(select * from TABLE Where CCC='D' AND DDD='X') as t1, 
(select * from TABLE Where CCC<>'D' AND DDD='X') as t2 

Một cách khác để thực hiện việc này!

+0

Thử nghiệm đơn giản của một bảng cột đơn với 2 hàng và sử dụng truy vấn đó để chọn đầu tiên là t1 và thứ hai là t2, không thành công, chỉ trả về t1. – Wolf5

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