COUNTIF集計関数に相当するSQL Server


164

GROUP BY特定の条件のみに基づいてレコードをカウントする機能が必要な句を使用してクエリを作成しています(たとえば、特定の列の値が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

というCOUNTIF()ネイティブSQL関数がないため、この行は明らかに失敗しますCOUNTIFが、ここでの考え方は、MyColumnの値が「1」であるすべての行のパーセンテージを決定することです。

これをMS SQL 2005環境に適切に実装する方法についての考えはありますか?

回答:


339

次のように、SUM(ではなくCOUNTCASEステートメントと組み合わせて使用できます。

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

注:私自身のテストでNULLは問題はありませんでしたが、これは環境に依存する可能性があります。次のようなnullを処理できます。

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

3
SQLiteのは、何を持っている(私はOPはMS SQLについて尋ねたが、SQLiteのユーザーのためだけの小さなコメントが同じことをやって知っている)ISNULL、代わりにあなたが行うことはできないCASE WHEN myColumn IS NULL、または使用ifnullstackoverflow.com/a/799406/1861346
マット・

54

私は通常、Joshが推奨することを行いますが、共有したいと思った少し面倒な代替案についてブレインストーミングし、テストしました。

COUNT(ColumnName)はNULLをカウントしないという事実を利用して、次のようなものを使用できます。

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

NULLIF-渡された2つの値が同じ場合、NULLを返します。

利点:SUM()表記ではなく、COUNT行に意図を表現します。欠点:動作が明確ではありません(通常、「魔法」は良くありません)。


2
グループのみヌルが含まれている場合、このソリューション缶は、それが1ではなく0のにつながる合計よりも異なる答えを与える
KimvdLinde

古い投稿ですが、これは役に立ちました。私は魔法を拡張し、ISNULL次のように追加することで「nullのみ」の問題を回避しましたSELECT COUNT(NULLIF(0, ISNULL(myColumn, 0)))。ちょっと、見た目が醜い...
pcdev 2017年

1
NULLIFNOT関数があったら完璧でしょう
qwertzguy

21

この構文を使用します。JoshとChrisの提案と同じですが、利点はANSIに準拠しており、特定のデータベースベンダーに依存していません。

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

2
Chrisの答えはStndard SQLに準拠しています(ヒント:NULLIF標準SQL-92が含まれています)。ジョシュの答えは簡単に交換することにより、標準SQLに変換することが可能isnullCOALESCE
onedaywhen

クリスが示していた「行を数える」という考え方が得られるので、私は実際にこの答えが一番好きですが、比較演算子を使用できるため、より拡張性があります。だけではありません=。私はそれを「応答数のカウント> = 2」に使用しています。
Kristen Hammack 2017年

3

ジョシュの答えに加えて、

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

(SQL Server 2012では)「カウント」を「合計」に変更せずにうまく機能し、同じロジックを他の「条件付き集計」に移植できます。たとえば、条件に基づいた合計:

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

2

いかがですか

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

より短い CASE:)

COUNT()はnull値をカウントしないため機能し、IF/ CASE条件が満たされていない場合はnullを返しますELSE

を使用するよりも良いと思いますSUM()


1

製品固有ではありませんが、SQL標準が提供する

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

この目的のために。それとよく似ているのか、帽子をかぶっているかはわかりません。

そしてもちろん、ベンダーは独自のソリューションを使い続けることを好みます。


1
これまで聞いたことがないので調べました。modern-sql.com/feature/filterによると、このFILTER句を実際に提供する主要なDBMS はPostgreSQLだけですがCASE、すべてのによってエミュレートされています。
Kristen Hammack 2017年

1

なぜこれが好きではないのですか?

SELECT count(1)
FROM AD_CurrentView
WHERE myColumn=1

1
彼は数だけではなく、もっとたくさんのことを必要としているからです。彼はグループの一部の行数を取得しようとしていて、グループ全体の集計を取得しようとしています。これはWHEREでは実行できません。
Kristen Hammack 2017年

1

私のケースでは、SELECT列の一部としてCOUNTIF()を使用し、結果に各項目が出現した回数の%を模倣する必要がありました。

だから私はこれを使った...

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

もちろん、表示要件に従って結果をフォーマットする必要があります。


-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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.