Máy chủ Sql tương đương với hàm tổng hợp COUNTIF


164

Tôi đang xây dựng một truy vấn với một GROUP BYmệnh đề cần khả năng đếm các bản ghi chỉ dựa trên một điều kiện nhất định (ví dụ: chỉ đếm các bản ghi trong đó một giá trị cột nhất định bằng 1).

SELECT  UID, 
        COUNT(UID) AS TotalRecords, 
        SUM(ContractDollars) AS ContractDollars,
        (COUNTIF(MyColumn, 1) / COUNT(UID) * 100) -- Get the average of all records that are 1
FROM    dbo.AD_CurrentView
GROUP BY UID
HAVING  SUM(ContractDollars) >= 500000

Các COUNTIF()dòng rõ ràng là thất bại vì không có chức năng SQL bản địa gọi COUNTIF, nhưng ý tưởng ở đây là để xác định tỷ lệ phần trăm của tất cả các hàng có giá trị '1' cho MyColumn.

Bạn có suy nghĩ gì về cách thực hiện đúng điều này trong môi trường MS SQL 2005 không?

Câu trả lời:


339

Bạn có thể sử dụng một SUM(không COUNT!) Kết hợp với một CASEtuyên bố, như thế này:

SELECT SUM(CASE WHEN myColumn=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

Lưu ý: trong thử nghiệm của riêng tôi NULLkhông phải là một vấn đề, mặc dù điều này có thể phụ thuộc vào môi trường. Bạn có thể xử lý các null như:

SELECT SUM(CASE WHEN ISNULL(myColumn,0)=1 THEN 1 ELSE 0 END)
FROM AD_CurrentView

3
(Tôi biết OP đã hỏi về MS SQL, nhưng chỉ là một nhận xét nhỏ cho người dùng SQLite làm điều tương tự) SQLite không có ISNULL, thay vào đó bạn có thể làm CASE WHEN myColumn IS NULLhoặc sử dụng ifnull( stackoverflow.com/a/799406/1861346 )
Matt

54

Tôi thường làm những gì Josh đề nghị, nhưng đã động não và thử nghiệm một sự thay thế hơi nhỏ mà tôi cảm thấy muốn chia sẻ.

Bạn có thể tận dụng thực tế là COUNT (Cột Tên) không tính NULL và sử dụng cái gì đó như thế này:

SELECT COUNT(NULLIF(0, myColumn))
FROM AD_CurrentView

NULLIF - trả về NULL nếu hai giá trị được truyền bằng nhau.

Ưu điểm: Thể hiện ý định của bạn với COUNT hàng thay vì có ký hiệu SUM (). Nhược điểm: Không rõ ràng như thế nào nó hoạt động ("ma thuật" thường là xấu).


2
Giải pháp này có thể đưa ra một câu trả lời khác với tổng khi một nhóm chỉ chứa null, kết quả là 1 thay vì 0.
KimvdLinde

Bài cũ, nhưng nhờ điều này đã giúp. Tôi đã mở rộng phép thuật và giải quyết vấn đề "chỉ null" bằng cách thêm vào ISNULLnhư sau : SELECT COUNT(NULLIF(0, ISNULL(myColumn, 0))). Đợi đã, trông nó thật xấu xí ...
pcdev

1
Sẽ là hoàn hảo nếu có chức năng
NULLIFNOT

21

Tôi sẽ sử dụng cú pháp này. Nó đạt được giống như đề xuất của Josh và Chris, nhưng với ưu điểm là ANSI tuân thủ và không bị ràng buộc với một nhà cung cấp cơ sở dữ liệu cụ thể.

select count(case when myColumn = 1 then 1 else null end)
from   AD_CurrentView

2
Câu trả lời của Chris là Stndard SQL tuân thủ (gợi ý: NULLIFđược bao gồm Tiêu chuẩn SQL-92). Câu trả lời của Josh có thể dễ dàng chuyển đổi thành SQL chuẩn bằng cách thay thế isnullbằng COALESCE.
onedaywhen

Tôi thực sự thích câu trả lời này nhất, bởi vì nó có ý tưởng "đếm hàng" mà Chris đang hiển thị, nhưng có thể mở rộng hơn, vì bạn có thể sử dụng bất kỳ toán tử so sánh nào; không chỉ =. Tôi đang sử dụng nó cho "đếm số lượng phản hồi> = 2".
Kristen Võng

3

Thêm vào câu trả lời của Josh,

SELECT COUNT(CASE WHEN myColumn=1 THEN AD_CurrentView.PrimaryKeyColumn ELSE NULL END)
FROM AD_CurrentView

Hoạt động tốt với tôi (trong SQL Server 2012) mà không thay đổi 'đếm' thành 'tổng' và logic tương tự có thể di chuyển sang các 'tổng hợp có điều kiện' khác. Ví dụ: tổng kết dựa trên một điều kiện:

SELECT SUM(CASE WHEN myColumn=1 THEN AD_CurrentView.NumberColumn ELSE 0 END)
FROM AD_CurrentView

2

Làm thế nào về

SELECT id, COUNT(IF status=42 THEN 1 ENDIF) AS cnt
FROM table
GROUP BY table

Ngắn hơn CASE:)

Hoạt động vì COUNT()không tính giá trị null và IF/ CASEtrả về null khi điều kiện không được đáp ứng và không có ELSE.

Tôi nghĩ rằng nó tốt hơn so với việc sử dụng SUM().


1

Không dành riêng cho sản phẩm, nhưng tiêu chuẩn SQL cung cấp

SELECT COUNT() FILTER WHERE <condition-1>, COUNT() FILTER WHERE <condition-2>, ... FROM ...

vì mục đích này. Hoặc một cái gì đó gần giống với nó, tôi không biết trên mũ của tôi.

Và tất nhiên các nhà cung cấp sẽ thích gắn bó với các giải pháp độc quyền của họ.


1
Tôi chưa bao giờ nghe về điều này trước đây, vì vậy tôi tìm kiếm nó. Theo Modern-sql.com/feature/filter , DBMS chính duy nhất thực sự cung cấp FILTERmệnh đề là PostgreQuery, nhưng nó được mô phỏng bởi CASEtất cả chúng.
Kristen Võng

1

Tại sao không như thế này?

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1

1
Bởi vì anh ta cần nhiều hơn là chỉ tính. Anh ta đang cố gắng để có được số lượng của một phần của một nhóm, và sau đó là tổng hợp của cả nhóm, điều mà bạn không thể làm với WHERE.
Kristen Võng

1

Tôi đã phải sử dụng COUNTIF () trong trường hợp của mình như là một phần của các cột CHỌN VÀ để bắt chước% của số lần mỗi mục xuất hiện trong kết quả của tôi.

Vì vậy, tôi đã sử dụng ...

SELECT COL1, COL2, ... ETC
       (1 / SELECT a.vcount 
            FROM (SELECT vm2.visit_id, count(*) AS vcount 
                  FROM dbo.visitmanifests AS vm2 
                  WHERE vm2.inactive = 0 AND vm2.visit_id = vm.Visit_ID 
                  GROUP BY vm2.visit_id) AS a)) AS [No of Visits],
       COL xyz
FROM etc etc

Tất nhiên bạn sẽ cần định dạng kết quả theo yêu cầu hiển thị của bạn.


-2
SELECT COALESCE(IF(myColumn = 1,COUNT(DISTINCT NumberColumn),NULL),0) column1,
COALESCE(CASE WHEN myColumn = 1 THEN COUNT(DISTINCT NumberColumn) ELSE NULL END,0) AS column2
FROM AD_CurrentView
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.