SQL HAVING: 初心者が理解しやすい集計条件の解説

データベースを扱うときには、特定の条件に基づいてデータを集計することが頻繁にあります。

SQLでは、このような集計条件を指定するために「HAVING」が利用できます。この記事では、SQL初心者にも理解しやすいように、HAVINGの基本概念や利用シーン、実際の使い方を解説していきます。

これを読めば、SQLでの集計条件の指定がスムーズに行えるようになるでしょう。

目次

SQL HAVINGとは?

SQL HAVINGは、データを集計した結果に対して特定の条件を適用するときに使います。HAVINGはGROUP BY句と組み合わせて使用され、集計関数などを利用した条件指定が可能です。

HAVINGの基本概念

HAVINGは、通常、SELECT文のGROUP BY句の後に記述されます。

基本的な構文は「HAVING [集計関数] [比較演算子] [値]」で、集計関数の結果が指定した値と比較演算子で比較され、条件に合致するデータが抽出されます。

HAVING [集計関数] [比較演算子] [値] 

集計関数には、COUNT(), SUM(), AVG(), MIN(), MAX()などが利用できます。また、比較演算子には、=, <>, >, <, >=, <= などが使用できます。

HAVINGの利用シーン

ここでは、基本となるHAVINGの利用シーンを紹介します。

特定条件の集計結果を抽出

グループ化したデータのうち、特定の条件を満たすものだけを抽出する場合に使います。たとえば、カテゴリ別に商品をグループ化し、その中で売上数が一定以上のカテゴリだけを抽出することができます。

グループ化したデータの条件抽出

グループ化したデータのうち、特定の条件を満たすものだけを抽出する場合に使います。たとえば、カテゴリ別に商品をグループ化し、その中で売上数が一定以上のカテゴリだけを抽出することができます。

特定の条件を満たすグループの抽出

HAVINGは、データをグループ化した上で、そのグループごとに条件を満たすものだけを抽出する際に利用されます。たとえば、顧客別の購入金額を集計し、特定の金額を超える顧客だけをリストアップすることができます。


これらの利用シーンでは、HAVINGを使用することで、効率的にデータを抽出することができます。ただし、HAVINGを使って集計条件を指定する際には注意点もあります。たとえば、HAVINGの順序やNull値が含まれる場合の懸念点、そしてHAVINGがパフォーマンスに与える影響について、理解しておくことが必要になります。

この記事では、これらの注意点や応用例についても詳しく解説していきます。

HAVINGのエイリアスについて

エイリアスとは、カラム名に別名を付けることで、SQL文の可読性を向上させたり、処理を簡潔に表現できるようにするために使用されます。HAVINGでは、集計関数を用いたカラムにエイリアスを使用して条件を指定することができますが、各データベース管理システムによって、エイリアスの使用可否が異なります。

本節では、主要なRDBMSであるMySQL、PostgreSQL、Oracle、SQL Serverのエイリアス使用可否について説明します。

MySQL、SQL Serverでエイリアスが使用可能

MySQLおよびSQL Serverでは、HAVINGでエイリアスを使用することができます。そのため、集計関数を適用したカラムに対して簡潔に条件を指定することが可能になります。たとえば、次のようにHAVINGでエイリアスを使うことができます。

SELECT category, COUNT(*) as num_products
FROM products
GROUP BY category
HAVING num_products > 5;

PostgreSQL、Oracleでエイリアスが使用不可

一方、PostgreSQLおよびOracleでは、HAVINGでエイリアスを直接使用することはできません。そのため、条件指定には集計関数を再度記述する必要があります。上記の例をPostgreSQLやOracleで実行する場合は、次のように記述する必要があります

SELECT category, COUNT(*) as num_products
FROM products
GROUP BY category
HAVING COUNT(*) > 5;

RDBMSごとに、エイリアスの使用可否に注意して、適切なSQL文を記述しなければなりません。各RDBMSの仕様を理解し、適切な記述方法でHAVINGを使用しましょう。

HAVINGの使い方

HAVINGは集計関数と組み合わせて使用します。ここでは、集計関数とHAVINGの組み合わせ、比較演算子、複数条件の指定方法について解説します。

集計関数とHAVINGの組み合わせ

HAVINGは、主に集計関数(SUM、COUNT、AVG、MIN、MAXなど)と組み合わせて使用します。グループ化されたデータに対して条件を設定し、条件を満たすグループだけを抽出することができます。

たとえば、顧客ごとの購入金額の合計が10,000円以上の顧客を抽出する場合、次のようなクエリを実行します。

SELECT product_category, SUM(quantity) as total_quantity
FROM sales_data
GROUP BY product_category

HAVING total_quantity > 15; -- MySQL、SQL Server

HAVING SUM(quantity)  > 15; -- PostgresQL、Oracle

このクエリでは、ordersテーブルのデータを顧客ID(customer_id)ごとにグループ化し、各顧客の購入金額の合計を計算しています。その後、HAVINGを使用して、購入金額の合計が10,000円以上の顧客だけを抽出しています。

集計関数とHAVINGの組合せ例: データベースの表: sales_data

idproduct_categorysale_datequantity
1Electronics2022-01-0110
2Electronics2022-01-025
3Furniture2022-01-038
4Electronics2022-01-0412
5Furniture2022-01-056
HAVING前

product_categoryTotal_quantity
Electronics27
HAVING SUM(quantity) > 15;

HAVINGで使用できる比較演算子

HAVINGでは、以下の比較演算子を使用して条件を指定することができます。

  • = (等しい)
  • <> または != (等しくない)
  • > (より大きい)
  • < (より小さい)
  • >= (以上)
  • <= (以下)

これらの比較演算子を組み合わせて、さまざまな条件を設定することができます。

複数条件の指定方法

HAVINGでは、複数の条件を指定することができます。条件を組み合わせるには、ANDORなどの論理演算子を使用します。たとえば、顧客ごとの購入金額の合計が10,000円以上で、かつ5件以上の注文がある顧客を抽出する場合、次のようなクエリを実行します。

SELECT customer_id, COUNT(*) as order_count, SUM(total_amount) as total_spent
FROM order_data
GROUP BY customer_id

HAVING order_count >= 2 AND total_spent >= 200; --  MySQL、SQL Server

HAVING COUNT(*) >= 2 AND SUM(total_amount) >= 200; -- PostgresQL、Oracle

このクエリでは、HAVINGで2つの条件(購入金額の合計が10,000円以上、注文数が5件以上)を指定し、両方の条件を満たす顧客だけを抽出しています。

複数条件を指定した例: データベースの表: order_data

idcustomer_idorder_datetotal_amount
112022-01-01100
212022-01-15200
322022-01-20150
422022-01-2550
532022-01-30300
HAVING前

customer_idorder_counttotal_spent
22200
12300
HAVING COUNT(*) >= 2 AND SUM(total_amount) >= 200;

上記のように、HAVINGを使用して集計関数と条件を組み合わせることで、データ分析やレポート作成などのさまざまなシーンで効果的に活用できるようになります。ただし、HAVINGを使用する際には、以下の点に注意してください。

  • HAVINGは、GROUP BY句と一緒に使用することが一般的です。GROUP BY句なしでHAVINGを使用することも可能ですが、その場合、全体の集計結果に対して条件を適用することになります。
  • MySQLやSQL Serverの場合、HAVINGの条件にはSELECT句で指定した別名(エイリアス)を使用することができます。ただし、PostgreSQLやSQL Serverの場合、エラーが発生しますので注意が必要です。
  • HAVINGの前に、WHEREを使用してレコードを絞り込むことができます。不要なデータを除外した上で集計や条件指定を行うことができます。

以上の点を理解することで、さまざまなシチュエーションでHAVINGを活用できるようになります。データ分析やレポート作成の際に、より柔軟な条件設定や効率的な集計が可能になります。

HAVINGとWHEREの違い

SQLの検索条件を指定するためには、HAVINGとWHEREが用いられますが、それぞれに違いがあります。

この章では、HAVINGとWHEREの違いについて、条件指定のタイミング、適用されるデータの種類、それぞれの使用場面に分けて解説していきます。

条件指定のタイミング

まず、HAVINGとWHEREの最も大きな違いは、条件指定のタイミングです。

  • WHERE:データを集約する前に、テーブルの行をフィルタリングするために使用されます。WHEREで指定された条件に一致する行のみが、その後の集約処理や選択処理に渡されます。
  • HAVING:データを集約した後に、集約結果をフィルタリングするために使用されます。HAVINGは、集約関数(COUNT、SUM、AVGなど)を使用したクエリにおいて、特定の条件に一致する集約結果のみを抽出するときに利用されます。

適用されるデータの種類

次に、適用されるデータの種類にも違いがあります。

  • WHERE:WHEREは、テーブルの個々の行に対して適用されるため、通常のカラムを使用して条件を指定します。
  • HAVING:HAVINGは、集約結果に対して適用されるため、集約関数を使用して条件を指定します。ただし、一部のRDBMSではエイリアスを使って条件指定を行うことはできません。

それぞれの使用場面

最後に、それぞれの使用場面について説明します。

  • WHERE:特定の条件に一致する行を抽出する際に使用されます。たとえば、特定の地域にある店舗のデータを抽出する場合や、特定の価格帯の商品を検索する場合などです。
  • HAVING:集約したデータに対して条件を指定する場合に使用されます。たとえば、特定の売上額を超える商品カテゴリを抽出する場合や、特定の期間に一定数以上の注文があった顧客を検索する場合などです。

HAVINGとWHEREの違いを理解することで、それぞれを適切な場面で活用することができます。条件指定のタイミングや適用されるデータの種類、使用場面を考慮して、最適なクエリを作成することがデータ抽出の効率化につながります。

例として、以下にそれぞれの節を使ったSQLクエリを示します。

— WHEREを使った例: 価格が5000円以上の商品を抽出

SELECT * FROM products
WHERE price >= 5000;

— HAVINGを使った例: カテゴリごとの売上額が10万円以上のカテゴリを抽出

SELECT category, SUM(sales_amount) AS total_sales
FROM sales
GROUP BY category

HAVING total_sales >= 100000; -- MySQL、SQL Server

HAVING SUM(sales_amount) >= 100000; -- PostgreSQL、Oracle

上記のように、HAVINGとWHEREを適切に使い分けることで、データ抽出や集計処理を効果的に行うことができます。また、HAVINGとWHEREを組み合わせて使用することも可能です。より複雑な条件でデータを抽出・集計することができるようになります。

例:– 価格が5000円以上の商品のカテゴリごとの売上額が10万円以上のカテゴリを抽出

SELECT category, SUM(sales_amount) AS total_sales
FROM sales
WHERE price >= 5000
GROUP BY category

HAVING total_sales >= 100000; -- MySQL、SQL Server

HAVING SUM(sales_amount) >= 100000; -- PostgreSQL、Oracle

このように、HAVINGとWHEREを理解し適切に使い分けることで、SQLクエリの効率を向上させることができます。

HAVINGの注意点

HAVINGを使用する際には、いくつかの注意点があります。この章では、HAVINGの順序やNull値の扱い、パフォーマンスへの影響について解説します。

HAVINGの順序に注意

SQLクエリの構文の中でHAVINGを使用するときには、その順序に注意が必要です。HAVINGは、GROUP BY句の後に記述する必要があります。さらに、ORDER BY句がある場合は、その前に記述します。

以下は、正しい順序でHAVINGが記述されたSQLクエリの例です。

SELECT category, COUNT(*) as num_products
FROM products
GROUP BY category

HAVING num_products > 5 -- MySQL、SQL Server
ORDER BY num_products DESC; -- MySQL、SQL Server

HAVING COUNT(*) > 5 -- PostgreSQL、Oracle
ORDER BY COUNT(*) DESC; -- PostgreSQL、Oracle

このクエリでは、カテゴリごとの商品数を集計し、商品数が5を超えるカテゴリのみ抽出した後、商品数の多い順に並べ替えています。

Null値の扱い

HAVINGで集計関数を使用するときには、Null値の扱いに注意が必要です。集計関数の中でNull値が存在する場合、その値は無視されます。例えば、以下のクエリを考えてみましょう。

SELECT category, AVG(price) as average_price
FROM products
GROUP BY category

HAVING average_price > 10000; -- MySQL、SQL Server

HAVING AVG(price) > 10000; -- PostgreSQL、Oracle

このクエリでは、カテゴリごとに平均価格を計算し、平均価格が10,000円より高いカテゴリを抽出しています。ただし、priceカラムにNull値が存在する場合、その値は平均計算から除外されます。

そのため、Null値が存在する場合は、その点を考慮して処理を行う必要があります。

HAVINGのパフォーマンスへの影響

HAVINGを使用するときには、パフォーマンスへの影響も考慮する必要があります。複雑な条件を指定すると、データベースの処理負荷が高くなり、クエリの実行時間が長くなる可能性があります。

パフォーマンスを向上させるためには、以下のような方法が考えられます。

  1. インデックスを適切に設定することで、検索や集計処理の効率を向上させることができます。
  2. SELECT句で指定するカラムを絞り込むことで、必要なデータのみを抽出することできます。
  3. 複雑な条件を指定する場合、サブクエリやCTE(Common Table Expression)を使用して、クエリを段階的に実行することで処理の効率を向上させることができます。
SELECT category, AVG(price) as average_price, SUM(quantity) as total_quantity
FROM products
GROUP BY category

HAVING average_price > 10000 AND total_quantity > 100; -- MySQL、SQL Server

HAVING AVG(price) > 10000 AND SUM(quantity) > 100; -- PostgreSQL、Oracle

このような場合、サブクエリを使用してクエリを分割することで、パフォーマンスを改善できる場合があります。

SELECT *
FROM (
    SELECT category, AVG(price) as average_price, SUM(quantity) as total_quantity
    FROM products
    GROUP BY category
) as subquery

WHERE average_price > 10000 AND total_quantity > 100; -- MySQL、SQL Server

WHERE AVG(price) > 10000 AND SUM(quantity) > 100; -- PostgreSQL、Oracle

HAVINGを使用するときは、注意点を把握して適切な方法で条件を指定しましょう。これにより、データの分析や抽出が効率的かつ正確に行えるようになります。

HAVINGを使った高度な集計条件

この章では、HAVINGを使った高度な集計条件のサンプルを2つ解説します。

サブクエリを利用して、他のテーブルとの比較を行う

サブクエリを利用して、他のテーブルとの比較を行うことができます。たとえば、以下のSQL文は、各カテゴリの平均価格が全体の平均価格よりも高いカテゴリを抽出します。

SELECT category, AVG(price) as average_price
FROM products
GROUP BY category
HAVING AVG(price) > (SELECT AVG(price) FROM products);

グループ化した結果に対して、さらにグループ化を行う(ネストしたグループ化)

グループ化した結果に対して、さらにグループ化を行うことで、複数の階層での集計が可能になります。たとえば、以下のSQL文は、年ごとの月ごとの売上金額が一定額以上の月を抽出します。

SELECT EXTRACT(YEAR FROM order_date) AS year, EXTRACT(MONTH FROM order_date) AS month, SUM(price * quantity) as total_sales
FROM orders
GROUP BY year, month
HAVING total_sales > 50000
ORDER BY year, month;

まとめ

本記事では、SQLの初心者向けにHAVINGを解説しました。

HAVINGは、集計関数を使った条件指定を行い、特定の条件を満たすグループのデータを抽出するために使用します。WHEREとの違いや注意点、さらに高度な集計条件の指定方法など、HAVINGの基本的な使い方から応用までを学ぶことができたと思います。

本記事がSQLの学習において、HAVINGを理解し活用する上での有益な情報となり、データ分析スキルを向上させるきっかけになれば幸いです。

目次