2009-05-12 38 views
5

Tôi đang sử dụng SQL Server 2005. Với truy vấn dưới đây (đơn giản hóa từ truy vấn thật của tôi):Đếm giá trị khác biệt và Null được loại bỏ bởi một tổng hợp

select a,count(distinct b),sum(a) from 
(select 1 a,1 b union all 
select 2,2 union all 
select 2,null union all 
select 3,3 union all 
select 3,null union all 
select 3,null) a 
group by a 

Có cách nào để làm một số khác biệt mà không cần nhận được

"Cảnh báo: Giá trị rỗng được loại bỏ bằng phép toán tổng hợp hoặc hoạt động SET khác".

Sau đây là các lựa chọn thay thế tôi có thể nghĩ:

  1. ANSI_WARNINGS Tắt
  2. Tách thành hai truy vấn, một với số lượng khác nhau và một mệnh đề where để loại bỏ null, một với tổng:

    select t1.a, t1.countdistinctb, t2.suma from 
    (
        select a,count(distinct b) countdistinctb from 
        (
         select 1 a,1 b union all 
         select 2,2 union all 
         select 2,null union all 
         select 3,3 union all 
         select 3,null union all 
         select 3,null 
        ) a 
        where a.b is not null 
        group by a 
    ) t1 
    left join 
    (
        select a,sum(a) suma from 
        (
         select 1 a,1 b union all 
         select 2,2 union all 
         select 2,null union all 
         select 3,3 union all 
         select 3,null union all 
         select 3,null 
        ) a 
        group by a 
    ) t2 on t1.a=t2.a 
    
  3. Bỏ qua các cảnh báo trong các khách hàng

Có cách nào tốt hơn để thực hiện việc này không? Tôi có thể sẽ đi xuống tuyến đường 2, nhưng không thích sao chép mã.

+0

Tôi nghĩ rằng mã cũ của bạn là tốt, cơ sở dữ liệu không nên rắc rối bạn với những bất ngờ đó là lý do tại sao nó tăng một cảnh báo, bởi vì một số lập trình viên có thể nghiêng để nghĩ rằng DISTINCT nên bao gồm đếm nulls dù sao đi nữa. Tôi nghĩ rằng cảnh báo cảnh báo là ANSI SQL-conforming. –

+0

Giải thích của bạn có ý nghĩa. Tuy nhiên, tôi không thích cảnh báo nếu tôi có thể tránh được chúng. –

Trả lời

5
select a,count(distinct isnull(b,-1))-sum(distinct case when b is null then 1 else 0 end),sum(a) from 
    (select 1 a,1 b union all 
    select 2,2 union all 
    select 2,null union all 
    select 3,3 union all 
    select 3,null union all 
    select 3,null) a 
    group by a 

Nhờ Eoin tôi làm việc ra một cách để làm điều này. Bạn có thể đếm các giá trị khác nhau bao gồm cả các giá trị rỗng và sau đó loại bỏ số do các giá trị rỗng nếu có bất kỳ giá trị nào bằng cách sử dụng một số tiền riêng biệt.

2

Anywhere bạn có một null có thể quay trở lại, sử dụng

CASE WHEN Column IS NULL THEN -1 ELSE Column END AS Column 

Điều đó sẽ phụ ra tất cả các giá trị Null cho -1 trong suốt thời gian truy vấn và họ sẽ được tính/tổng hợp như vậy, sau đó bạn chỉ có thể làm điều ngược lại trong truy vấn tốt gói của bạn ...

SELECT 
    CASE WHEN t1.a = -1 THEN NULL ELSE t1.a END as a 
    , t1.countdistinctb 
    , t2.suma 
+0

Tôi muốn tránh chia tách thành hai truy vấn và kết hợp. Nhờ ý tưởng của bạn tôi đã làm việc nó ra mặc dù, tôi sẽ gửi một câu trả lời. –

+0

Không thích ý tưởng này chút nào! Nếu dữ liệu đến trễ thì sao? Hoặc 'không rõ' là một trạng thái hoàn toàn hợp lệ? –

+0

Tôi đặc biệt thiết kế cho một trường hợp mà tôi không muốn bao gồm các giá trị NULL trong số. –

1

Nếu bạn không thích sao chép mã thì tại sao không sử dụng biểu thức bảng chung? ví dụ.

WITH x(a, b) AS 
     (
       select 1 a,1 b union all 
       select 2,2 union all 
       select 2,null union all 
       select 3,3 union all 
       select 3,null union all 
       select 3,null 
     ) 
select t1.a, t1.countdistinctb, t2.suma from 
(
     select a,count(distinct b) countdistinctb from 
     x a 
     where a.b is not null 
     group by a 
) t1 
left join 
(
     select a,sum(a) suma from 
     x a 
     group by a 
) t2 on t1.a=t2.a 
+0

Đó là một ý tưởng hay mà tôi chưa từng nghĩ tới. Nhưng sự trùng lặp mã tôi thực sự không thích là nhóm và tham gia, mà không thể loại bỏ được như thế này. Cảm ơn mặc dù. –

2

Đây là lưu ý muộn, nhưng đó là sự trở lại trên Google, tôi muốn đề cập đến nó.

Thay đổi NULL thành giá trị khác là một ý tưởng tồi (tm).

COUNT() đang làm việc đó, chứ không phải DISTINCT.

Thay vào đó, hãy sử dụng DISTINCT trong truy vấn phụ và trả về một số và tổng hợp số đó trong truy vấn bên ngoài.

Một ví dụ đơn giản của việc này là:

WITH A(A) AS (SELECT NULL UNION ALL SELECT NULL UNION ALL SELECT 1) 
SELECT COUNT(*) FROM (SELECT DISTINCT A FROM A) B; 

Điều này cho phép COUNT(*) được sử dụng, mà không bỏ qua NULLs (vì nó đếm hồ sơ, không giá trị).

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