SQLのHAVING句で集計後の絞り込み条件を設定:WHERE句との違いを理解して使い分ける

2024-04-15

SQL - HAVING vs WHERE: データ集約後の絞り込み条件

SQLにおける WHERE 句と HAVING 句はどちらもデータの絞り込み条件を定義するために使用されますが、適用されるタイミングと対象が異なります。

WHERE句

  • レコード全体を対象とした絞り込み条件を定義します。
  • 集計処理に適用されます。
  • 個々のレコード属性に基づいて条件を指定します。

HAVING句

  • 集計処理の結果に対して絞り込み条件を定義します。

社員テーブル (employee) を例に考えてみましょう。

employee_iddepartmentsalary
1Sales30000
2Engineering45000
3Marketing25000
4Sales40000
5Engineering50000
  • 営業部 (Sales) の社員のみ抽出:
SELECT * FROM employee WHERE department = 'Sales';
  • 平均給与が3万5千円以上の部署のみ抽出:
SELECT department, AVG(salary) AS avg_salary
FROM employee
GROUP BY department
HAVING avg_salary >= 35000;
  • WHERE 句は個々のレコード属性に基づいて絞り込みを行い、HAVING 句は集計結果に基づいて絞り込みを行います。
  • 集計処理前後で適用タイミングが異なるため、適切な句を選択することが重要です。

補足

  • HAVING 句は常に集計関数と一緒に使用されます。
  • WHERE 句と HAVING 句を組み合わせて使用することもできます。



状況

  • 社員テーブルには、社員ID、所属部署、給与が記録されています。
  • 営業部、エンジニアリング部、マーケティング部の3つの部署があります。
  • 各部署の平均給与と、平均給与が3万5千円以上の部署を知りたい。

テーブル構造

CREATE TABLE employee (
  employee_id INT PRIMARY KEY,
  department VARCHAR(255) NOT NULL,
  salary INT NOT NULL
);

データ

INSERT INTO employee VALUES
  (1, 'Sales', 30000),
  (2, 'Engineering', 45000),
  (3, 'Marketing', 25000),
  (4, 'Sales', 40000),
  (5, 'Engineering', 50000);

各部署の平均給与

方法1:WHERE 句を使用

各部署ごとにレコードを抽出し、個別に平均給与を計算します。

SELECT department, AVG(salary) AS avg_salary
FROM employee
GROUP BY department;

結果

departmentavg_salary
Sales35000
Engineering47500
Marketing25000

方法2:HAVING 句を使用

全レコードを対象に集計を行い、平均給与が3万5千円以上の部署のみ抽出します。

SELECT department, AVG(salary) AS avg_salary
FROM employee
GROUP BY department
HAVING avg_salary >= 35000;
departmentavg_salary
Sales35000
Engineering47500

平均給与が3万5千円以上の部署IDを取得するサブクエリを作成し、WHERE 句で条件を指定します。

SELECT *
FROM employee
WHERE department IN (
  SELECT department
  FROM employee
  GROUP BY department
  HAVING avg_salary >= 35000
);
employee_iddepartmentsalary
1Sales30000
4Sales40000
2Engineering45000
5Engineering50000
SELECT department, AVG(salary) AS avg_salary
FROM employee
GROUP BY department
HAVING avg_salary >= 35000;
departmentavg_salary
Sales35000
Engineering47500

考察

  • 方法1と方法2でそれぞれ異なるSQL文を作成しましたが、結果は同じです。
  • 状況に応じて、適切な方法を選択することが重要です。
  • サンプルコードでは、集計関数 AVG を使用していますが、SUMCOUNT などの他の集計関数も同様に使用できます。



SQLにおける WHERE 句と HAVING 句以外の代替方法

ウィンドウ関数

近年、多くのデータベースで搭載され始めたウィンドウ関数は、集計処理を行いながら個々のレコードに対して条件を評価することができます。

例:ROW_NUMBER 関数を利用した各部署の平均給与が3万5千円以上の社員を抽出

SELECT *
FROM employee
WHERE ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary) <= CEILING(AVG(salary) OVER (PARTITION BY department) * 1.15)

利点

  • 集計処理と条件評価を1つのクエリで完結できるため、コードが簡潔になる。
  • WHERE 句と HAVING 句よりも柔軟な条件設定が可能。

欠点

  • 比較的新しく導入された機能のため、対応していないデータベースがある。
  • 従来の WHERE 句や HAVING 句よりも処理速度が遅い場合がある。

CTE (Common Table Expression)

CTEは、一時的な結果セットを定義できる機能です。この機能を利用して、複雑な条件を複数回に分けて処理することで、WHERE 句や HAVING 句の制約を回避することができます。

WITH avg_salary AS (
  SELECT department, AVG(salary) AS avg_salary
  FROM employee
  GROUP BY department
)
SELECT *
FROM employee
WHERE department IN (
  SELECT department
  FROM avg_salary
  WHERE avg_salary >= 35000
)
  • 複雑な条件を複数回に分けて処理することで、可読性と理解しやすさを向上できる。
  • 複数のクエリを組み合わせるため、コードが冗長になる場合がある。
  • CTEをサポートしていないデータベースがある。

サブクエリは、別のクエリをクエリの中で利用する機能です。この機能を利用して、WHERE 句や HAVING 句の条件式に複雑なロジックを組み込むことができます。

SELECT *
FROM employee
WHERE department IN (
  SELECT department
  FROM (
    SELECT department, AVG(salary) AS avg_salary
    FROM employee
    GROUP BY department
  ) AS subquery
  WHERE avg_salary >= 35000
)
  • 複雑な条件をサブクエリにカプセル化することで、メインクエリをスッキリとさせることができる。
  • 再利用可能なサブクエリを作成することで、コードの保守性を向上できる。
  • ネストされたクエリ構造は、可読性と理解しやすさを損なう可能性がある。

WHERE 句と HAVING 句に加えて、ウィンドウ関数、CTE、サブクエリなどの代替方法も状況に応じて活用することで、より柔軟で効率的なデータ絞り込みを実現することができます。

それぞれの方法には利点と欠点があるため、状況に合わせて適切な方法を選択することが重要です。


sql where-clause having


ANALYZE TABLEコマンドを使用して重複データを見つける

Oracleデータベースでテーブル内の重複データを検索するには、いくつかの方法があります。GROUP BY句を使用するDISTINCTキーワードを使用するJOIN句を使用する方法の詳細GROUP BY句を使用して、同じ値を持つ行をグループ化できます。グループ内の行数が1より多い場合、その値は重複していることになります。...


実践的なSQLスキルアップ:異なる列数のテーブル結合でデータの力を引き出す

例次の2つのテーブルがあるとします。これらのテーブルを結合するには、次のクエリを使用できます。このクエリは、両方のテーブルのすべての列を含む結果セットを返します。tableA には city 列がありますが、tableB にはありません。この場合、city 列は NULL 値で表示されます。...


SQLクエリで特定のデータベースのすべてのテーブル名を取得する

INFORMATION_SCHEMA ビューは、データベースに関するメタデータ(テーブル名、列名、データ型など)へのアクセスを提供します。すべてのデータベースで利用可能な標準のビューなので、データベースの種類に関わらず、この方法を使用することができます。...


SQL を使用して SQLite データベースから重複行を削除する方法

SELECT DISTINCT は、重複する行を削除して、各行を1回だけ返すクエリです。これは、重複行を削除する最も簡単な方法です。このクエリは、テーブル名 テーブルのすべての列を返し、重複する行は削除されます。GROUP BY は、1つまたは複数の列に基づいて行をグループ化するクエリです。この機能を使用して、重複行を削除することもできます。...


PostgreSQLでGROUP BY句と集計関数を使用して1つの列の複数の結果行を1つに連結し、別の列でグループ化する際の注意点

例題:顧客テーブル customers があり、以下の列があります。customer_id: 顧客IDname: 顧客名city: 顧客の居住都市各都市に住む顧客の名前をカンマ区切りで連結したリストを取得したいと考えています。方法1:GROUP BY 句と STRING_AGG 関数を使用する...


SQL SQL SQL SQL Amazon で見る



【SQL】WHERE句とHAVING句の使い分けで、データ抽出をもっと効率的に!

WHERE句は、SELECT句で指定されたテーブルからデータを取得する際に、個々のレコードに対して条件を指定します。つまり、WHERE句で指定された条件を満たすレコードのみが抽出されます。例:この例では、department列がSalesで、salary列が100


これで完璧!WHERE句とHAVING句を使いこなしてデータ分析をマスターしよう

概要WHERE句WHERE句は、SELECT、UPDATE、DELETEなどのステートメントで使用できます。集計前に個々の行に対して条件を適用し、条件を満たす行のみを結果として返します。例:上記の例では、country列が日本である顧客のみが抽出されます。