MySQLでGROUP_CONCAT()とDISTINCTを使って、カテゴリーごとの重複商品名を連結する方法

2024-04-10

MySQLにおけるGROUP_CONCAT()とDISTINCTの組み合わせ

GROUP_CONCAT()とDISTINCTを組み合わせることで、グループ内の重複する値を除去した上で連結することができます。

使用例

SELECT
  category,
  GROUP_CONCAT(DISTINCT product_name) AS products
FROM products
GROUP BY category;

この例では、productsテーブルから、categoryと、categoryごとに重複する値を除去したproduct_nameの連結を取得します。

結果例

| category | products                          |
|----------|-----------------------------------|
| 食品     | リンゴ, バナナ, オレンジ, ブドウ |
| 家電     | テレビ, 冷蔵庫, 洗濯機, 掃除機 |
| 衣類     | シャツ, ズボン, スカート, ワンピース |

DISTINCTの注意点

DISTINCTは、GROUP_CONCAT()内の列に対してのみ適用されます。GROUP BYする列に対しては適用されません。

例:誤った使い方

SELECT
  DISTINCT category,
  GROUP_CONCAT(product_name) AS products
FROM products
GROUP BY category;

この例では、DISTINCTはcategoryに対して適用されますが、GROUP_CONCAT()内のproduct_nameには適用されません

| category | products                          |
|----------|-----------------------------------|
| 食品     | リンゴ, バナナ, オレンジ, ブドウ, リンゴ |
| 家電     | テレビ, 冷蔵庫, 洗濯機, 掃除機, テレビ |
| 衣類     | シャツ, ズボン, スカート, ワンピース, シャツ |

正しい使い方

SELECT
  category,
  GROUP_CONCAT(DISTINCT product_name) AS products
FROM products
GROUP BY category;
| category | products                          |
|----------|-----------------------------------|
| 食品     | リンゴ, バナナ, オレンジ, ブドウ |
| 家電     | テレビ, 冷蔵庫, 洗濯機, 掃除機 |
| 衣類     | シャツ, ズボン, スカート, ワンピース |
  • GROUP_CONCAT()には、SEPARATORオプションを使用して、連結文字列の区切り文字を指定することができます。

詳細は、MySQLのドキュメントを参照してください。




-- テーブル作成
CREATE TABLE products (
  id INT PRIMARY KEY AUTO_INCREMENT,
  category VARCHAR(255) NOT NULL,
  product_name VARCHAR(255) NOT NULL
);

-- データ挿入
INSERT INTO products (category, product_name) VALUES
  ('食品', 'リンゴ'),
  ('食品', 'バナナ'),
  ('食品', 'オレンジ'),
  ('食品', 'ブドウ'),
  ('食品', 'リンゴ'),
  ('家電', 'テレビ'),
  ('家電', '冷蔵庫'),
  ('家電', '洗濯機'),
  ('家電', '掃除機'),
  ('家電', 'テレビ'),
  ('衣類', 'シャツ'),
  ('衣類', 'ズボン'),
  ('衣類', 'スカート'),
  ('衣類', 'ワンピース'),
  ('衣類', 'シャツ');

-- クエリ実行
SELECT
  category,
  GROUP_CONCAT(DISTINCT product_name) AS products
FROM products
GROUP BY category;
| category | products                          |
|----------|-----------------------------------|
| 食品     | リンゴ, バナナ, オレンジ, ブドウ |
| 家電     | テレビ, 冷蔵庫, 洗濯機, 掃除機 |
| 衣類     | シャツ, ズボン, スカート, ワンピース |

その他のサンプル

  • SEPARATORオプションを使用して、連結文字列の区切り文字を指定する
SELECT
  category,
  GROUP_CONCAT(DISTINCT product_name SEPARATOR ', ') AS products
FROM products
GROUP BY category;
| category | products                          |
|----------|-----------------------------------|
| 食品     | リンゴ, バナナ, オレンジ, ブドウ |
| 家電     | テレビ, 冷蔵庫, 洗濯機, 掃除機 |
| 衣類     | シャツ, ズボン, スカート, ワンピース |
  • ORDER BYオプションを使用して、連結する値の順序を指定する
SELECT
  category,
  GROUP_CONCAT(DISTINCT product_name ORDER BY product_name ASC) AS products
FROM products
GROUP BY category;
| category | products                          |
|----------|-----------------------------------|
| 食品     | バナナ, ブドウ, リンゴ, オレンジ |
| 家電     | 掃除機, 洗濯機, 冷蔵庫, テレビ |
| 衣類     | ワンピース, スカート, ズボン, シャツ |

サンプルコードを参考に、さまざまな方法でGROUP_CONCAT()とDISTINCTを組み合わせてみてください。




GROUP_CONCAT()とDISTINCTを組み合わせるその他の方法

サブクエリを使用する

SELECT
  category,
  (
    SELECT GROUP_CONCAT(DISTINCT product_name)
    FROM products
    WHERE category = p.category
  ) AS products
FROM products AS p
GROUP BY category;

この方法は、サブクエリを使用して、各グループ内の重複する値を除去した上で連結します。

GROUP BY句でDISTINCTを使用する

SELECT
  category,
  GROUP_CONCAT(product_name) AS products
FROM (
  SELECT DISTINCT category, product_name
  FROM products
) AS t
GROUP BY category;

この方法は、GROUP BY句でDISTINCTを使用して、重複するレコードを事前に除去してからGROUP_CONCAT()を使用します。

ユーザー定義関数を使用する

DELIMITER //

CREATE FUNCTION group_concat_distinct(
  column_name VARCHAR(255)
) RETURNS VARCHAR(255)
DETERMINISTIC
BEGIN
  DECLARE result VARCHAR(255);
  DECLARE values VARCHAR(255);
  DECLARE cursor CURSOR FOR
    SELECT DISTINCT column_name
    FROM products;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET result = '';

  OPEN cursor;
  
  REPEAT
    FETCH cursor INTO values;
    SET result = CONCAT(result, values, ', ');
  UNTIL NOT FOUND;

  CLOSE cursor;

  RETURN LEFT(result, LENGTH(result) - 2);
END;
//

DELIMITER ;

SELECT
  category,
  group_concat_distinct(product_name) AS products
FROM products
GROUP BY category;

この方法は、ユーザー定義関数を使用して、GROUP_CONCAT()とDISTINCTの機能を組み込みます。

GROUP_CONCAT()とDISTINCTを組み合わせる方法は、いくつかあります。

それぞれの特徴を理解して、目的に合った方法を選択してください。


mysql group-concat


サンプルコード:MySQLで複数の列にユニーク制約を設定する

MySQLで複数の列にユニーク制約を指定するには、UNIQUE制約を使用します。この制約は、指定された列の組み合わせがテーブル内で一意であることを保証します。方法は2つあります。CREATE TABLE ステートメントを使用する例この例では、usersテーブルにはusernameとemail列にユニーク制約が設定されています。つまり、同じusernameまたは同じemailを持つユーザーは2人以上登録できません。...


【MySQL/SQL/SQL Server】LEFT OUTER JOINでNULLをデフォルト値に置き換える方法を徹底解説!

この場合、結果セットのNULL値をデフォルト値やその他の値に置き換えることが必要になる場合があります。以下、MySQL、SQL Server、共通の代替方法について説明します。MySQLでは、COALESCE() 関数を使用して、LEFT OUTER JOINで返されるNULL値をデフォルト値に置き換えることができます。...


MySQLエラー: キー長を指定せずにインデックスを作成する方法

このエラーが発生する理由は、次のとおりです。CREATE INDEX または ALTER TABLE ADD INDEX ステートメントで、KEY_LENGTH オプションが指定されていない。KEY_LENGTH オプションに、有効な値が指定されていない。...


【初心者向け】MySQL Workbenchでデータベース接続トラブルを解決!5つのステップでサクッと復旧

MySQL Workbenchでデータベースサーバーに接続できない場合、以下の点を確認することで問題を解決できる可能性があります。サーバーが起動していることを確認まず、MySQLサーバーが起動していることを確認してください。サーバーが起動していない場合は、起動してください。...


AWS RDSでGRANT ALL PRIVILEGESを実行した際に発生する「Access denied」エラーの解決方法

AWS RDSでGRANT ALL PRIVILEGES ON the_db. * TO 'the_user'@'%'コマンドを実行し、特定のデータベースに対するすべての権限をユーザーに付与しようとすると、「Access denied」エラーが発生する可能性があります。これは、RDSのセキュリティ対策により、デフォルトでは*.*に対する権限付与が制限されているためです。...