2013-07-31 55 views
8

nên basicially có 1 câu hỏi và 1 vấn đề:SQL sử dụng CASE trong SELECT bằng GROUP BY. Cần CASE-giá trị nhưng nhận hàng có giá trị

1. Câu hỏi - khi tôi có như 100 cột trong một bảng (và không có chìa khóa hoặc uindex được thiết lập) và Tôi muốn tham gia hoặc bỏ chọn bảng đó với chính nó, tôi có thực sự phải viết ra mỗi tên cột?

2. vấn đề - ví dụ dưới đây cho thấy 1. câu hỏi và vấn đề SQL tuyên bố thực tế của tôi

Ví dụ:

A.FIELD1, 
(SELECT CASE WHEN B.FIELD2 = 1 THEN B.FIELD3 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD1 
(SELECT CASE WHEN B.FIELD2 = 2 THEN B.FIELD4 ELSE null FROM TABLE B WHERE A.* = B.*) AS CASEFIELD2 
FROM TABLE A 
GROUP BY A.FIELD1 

Câu chuyện là: nếu tôi không đặt TRƯỜNG HỢP vào tuyên bố chọn riêng của nó sau đó tôi phải đặt các rowname thực tế vào GROUP BY và GROUP BY không nhóm NULL-giá trị từ CASE nhưng giá trị thực tế từ hàng. Và do đó tôi sẽ phải tham gia hoặc bỏ chọn với tất cả các cột, vì không có khóa và không có uindex, hoặc bằng cách nào đó tìm thấy một giải pháp khác.

DBServer là DB2.

Vì vậy, bây giờ để mô tả nó chỉ bằng các từ và không có SQL: Tôi có "mục đơn hàng" có thể được chia thành "ZD" và "EK" (1 = ZD, 2 = EK) và có thể được nhóm lại theo " nhà phân phối". Mặc dù "các mục đặt hàng" có thể có một trong hai "lần khởi hành" khác nhau (ZD, EK), các trường/hàng cho "ZD" và "EK" luôn được điền đầy. Tôi cần các nhóm để xem xét các "khởi hành" và chỉ khi được chỉ định "khởi hành" (ZD hoặc EK) đang thay đổi, sau đó tôi muốn một nhóm mới được tạo ra.

SELECT 
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD, 
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK, 
TABLE.DISTRIBUTOR, 
sum(TABLE.SOMETHING) AS SOMETHING, 
FROM TABLE 
GROUP BY 
ZD 
EK 
TABLE.DISTRIBUTOR 
TABLE.DEPARTEMENT 

Điều này ở đây hoạt động trong SELECT và ZD, EK trong GROUP BY. Chỉ có vấn đề là, ngay cả khi EK không phải là DEPARTEMENT được chỉ định, nó vẫn mở một nhóm mới nếu nó thay đổi, bởi vì anh ta đang sử dụng giá trị EK thực và không phải là NULL từ CASE, như tôi đã giải thích hàng đầu.

+0

Bạn có nghĩa là kiểm tra giá trị của mỗi cột của bảng A đến cột trong bảng b với cùng tên cột và tất cả các cột phải khớp nhau? Hay bạn có nghĩa là một số loại logic khác? – WarrenT

+0

Chính xác, nhưng đó chỉ là câu hỏi mặc dù và không phải là vấn đề thực sự, mà tôi sẽ cố gắng để giải thích thêm/tốt hơn trong thời gian gần. – Khazar

Trả lời

6

Và đây quý bà và quý ông sự là giải pháp cho vấn đề:

SELECT 
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END) AS ZD, 
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END) AS EK, 
TABLE.DISTRIBUTOR, 
sum(TABLE.SOMETHING) AS SOMETHING, 
FROM TABLE 
GROUP BY 
(CASE WHEN TABLE.DEPARTEMENT = 1 THEN TABLE.ZD ELSE null END), 
(CASE WHEN TABLE.DEPARTEMENT = 2 THEN TABLE.EK ELSE null END), 
TABLE.DISTRIBUTOR, 
TABLE.DEPARTEMENT 

@ t-clausen.dk: Cảm ơn bạn!

@others: ...

1

Không, không có kiểm tra bình đẳng ký tự đại diện. Bạn sẽ phải liệt kê mọi trường bạn muốn thử nghiệm riêng lẻ. Nếu bạn không muốn kiểm tra từng trường riêng lẻ, bạn có thể sử dụng một hack chẳng hạn như ghép tất cả các trường, ví dụ:

WHERE (a.foo + a.bar + a.baz) = (b.foo + b.bar + b.az) 

nhưng theo một trong hai cách, bạn liệt kê tất cả các trường.

+1

"+" không phải là toán tử nối, ví dụ của bạn sẽ thất bại nếu có cột không phải là số. Ngay cả khi bạn sử dụng kết nối thích hợp, nó sẽ không hoạt động chính xác trong nhiều trường hợp. Ví dụ: '' a '|| null || 'c'' và '' a '|| 'b' || null' cả hai sẽ trả về NULL, trong khi ý định rõ ràng sẽ là để điều trị các kết hợp này là khác nhau. Mặt khác, một giá trị NULL không bằng một giá trị NULL khác, do đó, '' a '|| null || 'c'' và '' a '|| null || 'c'' sẽ không bằng nhau, mặc dù ý định trong trường hợp này sẽ là đối xử với chúng như nhau. – mustaccio

+0

Xin hãy hét lên với cơ thể tiêu chuẩn SQL và yêu cầu họ giải quyết trên một nhà điều hành tiêu chuẩn, sau đó ... –

+0

Xin hãy hét lên với bất cứ ai bạn muốn. Chuẩn ANSI SQL xác định rõ ràng thanh dọc kép làm toán tử nối. – mustaccio

2

Thực tế có kiểm tra bình đẳng ký tự đại diện. Tôi không chắc chắn lý do tại sao bạn sẽ nhóm theo field1, điều đó dường như không thể trong ví dụ của bạn. Tôi cố gắng để phù hợp với nó vào câu hỏi của bạn:

SELECT FIELD1, 
CASE WHEN FIELD2 = 1 THEN FIELD3 END AS CASEFIELD1, 
CASE WHEN FIELD2 = 2 THEN FIELD4 END AS CASEFIELD2 
FROM 
(
SELECT * FROM A 
INTERSECT 
SELECT * FROM B 
) C 
UNION -- results in a distinct 
SELECT 
A.FIELD1, 
null, 
null 
FROM 
(
SELECT * FROM A 
EXCEPT 
SELECT * FROM B 
) C 

này sẽ thất bại cho kiểu dữ liệu mà không phải là so sánh

+0

Đây là một câu trả lời hay cho câu hỏi của tôi, nhưng thật đáng buồn là nó chỉ có thể theo cách lộn xộn như vậy. Bây giờ chỉ có vấn đề cần được giải quyết. – Khazar

+0

@Khazar có nó rất phức tạp. Nhưng chỉ muốn chứng minh rằng nó là có thể –

0

Nếu bạn cần phải tìm tất cả các hàng trong TableA phù hợp trong TableB, làm thế nào về INTERSECT hoặc INTERSECT DISTINCT?

select * from A 
INTERSECT DISTINCT 
select * from B 

Tuy nhiên, nếu bạn chỉ muốn các hàng từ A trong đó toàn bộ hàng khớp với giá trị trong hàng từ B thì tại sao mã mẫu của bạn lấy một số giá trị từ A và các giá trị khác từ B? Nếu hàng khớp với tất cả các cột thì điều đó có vẻ vô nghĩa. (Có lẽ câu hỏi của bạn có thể được giải thích đầy đủ hơn một chút?)

+0

Vấn đề là với GROUP BY và CASE. Tôi cần giá trị đến từ CASE nhưng tôi không thể sử dụng một bí danh (mà tôi cần phải làm vì tôi không muốn nhóm FIELD3, FIELD4 và các giá trị chưa được lọc của chúng) trừ khi tôi sử dụng một subselect. Vì vậy, có subselect thường là vô nghĩa, nhưng không phải trong trường hợp này. – Khazar

+0

Vui lòng giải thích (các) yêu cầu bằng tiếng Anh, bao gồm (nhưng không giới hạn) những gì bạn cần làm với logic CASE và logic phù hợp. Để lại SQL cho bây giờ. Chúng tôi có thể cung cấp điều đó, một khi chúng tôi hiểu rõ ràng và rõ ràng những gì cần phải làm, – WarrenT

+0

@ t-clausen Xin lỗi, không biết tại sao tôi không thấy câu trả lời của bạn trong khi đưa ra cho tôi. – WarrenT

1

tôi có thể có xu hướng để giải quyết nó một cái gì đó như thế này

WITH q as 
(SELECT 
     Department 
    , (CASE WHEN DEPARTEMENT = 1 THEN ZD 
      WHEN DEPARTEMENT = 2 THEN EK 
            ELSE null 
     END) AS GRP 
    , DISTRIBUTOR 
    , SOMETHING 
    FROM mytable 
) 
SELECT 
     Department 
    , Grp 
    , Distributor 

    , sum(SOMETHING) AS SumTHING 
    FROM q 
GROUP BY 
     DEPARTEMENT 
    , GRP 
    , DISTRIBUTOR