I have some data in a table like so:
product_id categories
10 9,12
11 8
12 11,18,5
I want a select statement that would produce this output:
product_id category_id
10 9
10 12
11 8
12 11
12 18
12 5
私はそれをググることができるようにこのシナリオをフレーズする方法がわかりません。
探しているのは、GROUP_CONCATを使用したGROUP BY集計クエリの逆です。結果を一時テーブルに格納することをいとわないなら、私はちょうどそれを得ました。
まず、prod
というテーブルとprodcat
という一時テーブルのサンプルデータを使用して、探している結果を保持するコードを次に示します。
use test
drop table if exists prod;
drop table if exists prodcat;
create table prod
(
product_id int not null,
categories varchar(255)
) engine=MyISAM;
create table prodcat
(
product_id int not null,
cat int not null
) engine=MyISAM;
insert into prod values
(10,'9,12'),(11,'8'),(12,'11,18,5');
select * from prod;
ここにロードされます
mysql> use test
Database changed
mysql> drop table if exists prod;
Query OK, 0 rows affected (0.00 sec)
mysql> drop table if exists prodcat;
Query OK, 0 rows affected (0.00 sec)
mysql> create table prod
-> (
-> product_id int not null,
-> categories varchar(255)
-> ) engine=MyISAM;
Query OK, 0 rows affected (0.07 sec)
mysql> create table prodcat
-> (
-> product_id int not null,
-> cat int not null
-> ) engine=MyISAM;
Query OK, 0 rows affected (0.06 sec)
mysql> insert into prod values
-> (10,'9,12'),(11,'8'),(12,'11,18,5');
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from prod;
+------------+------------+
| product_id | categories |
+------------+------------+
| 10 | 9,12 |
| 11 | 8 |
| 12 | 11,18,5 |
+------------+------------+
3 rows in set (0.00 sec)
mysql>
OK、各product_idと各カテゴリを組み合わせるクエリが必要です。ここにあります:
select concat('insert into prodcat select ',product_id,',cat from (select NULL cat union select ',
replace(categories,',',' union select '),') A where cat IS NOT NULL;') ProdCatQueries from prod;
ここで実行されます
mysql> select concat('insert into prodcat select ',product_id,',cat from (select NULL cat union select ',
-> replace(categories,',',' union select '),') A where cat IS NOT NULL;') ProdCatQueries from prod;
+----------------------------------------------------------------------------------------------------------------------------------+
| ProdCatQueries |
+----------------------------------------------------------------------------------------------------------------------------------+
| insert into prodcat select 10,cat from (select NULL cat union select 9 union select 12) A where cat IS NOT NULL; |
| insert into prodcat select 11,cat from (select NULL cat union select 8) A where cat IS NOT NULL; |
| insert into prodcat select 12,cat from (select NULL cat union select 11 union select 18 union select 5) A where cat IS NOT NULL; |
+----------------------------------------------------------------------------------------------------------------------------------+
3 rows in set (0.00 sec)
mysql>
各行を手動で実行させます
mysql> insert into prodcat select 10,cat from (select NULL cat union select 9 union select 12) A where cat IS NOT NULL;
Query OK, 2 rows affected (0.07 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> insert into prodcat select 11,cat from (select NULL cat union select 8) A where cat IS NOT NULL;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into prodcat select 12,cat from (select NULL cat union select 11 union select 18 union select 5) A where cat IS NOT NULL;
Query OK, 3 rows affected (0.00 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql>
いいよ。クエリは機能します。 prodcatテーブルは適切に入力されましたか?
mysql> select * from prodcat;
+------------+-----+
| product_id | cat |
+------------+-----+
| 10 | 9 |
| 10 | 12 |
| 11 | 8 |
| 12 | 11 |
| 12 | 18 |
| 12 | 5 |
+------------+-----+
6 rows in set (0.00 sec)
mysql>
わかりました。データがあります。
正直なところ、SQL Serverでは、手作りの一時テーブルがなくても、これらすべてを1つのピボットクエリで実行できると思います。
それを別のレベルにして、すべてのクエリを1つのクエリに連結することもできましたが、SQLは非常に長くなっていたでしょう。実際のクエリが数千行ある場合、単一のMySQLは実用的ではありませんでした。
3つのINSERTクエリを手動で実行する代わりに、3つのINSERTクエリをテキストファイルにエコーして、スクリプトとして実行できます。次に、製品とカテゴリの組み合わせを個別に記述したテーブルがあります。
組み込みのMySQLトリックス自体はありませんが、巧妙な方法で目標を達成するカスタムプロシージャを保存できます。 products
テーブルに列product_id
、categories
、および新しいcategory_id
があると仮定します。
DELIMITER $$
CREATE FUNCTION SPLIT_STRING(val TEXT, delim VARCHAR(12), pos INT) RETURNS TEXT
BEGIN
DECLARE output TEXT;
SET output = REPLACE(SUBSTRING(SUBSTRING_INDEX(val, delim, pos), CHAR_LENGTH(SUBSTRING_INDEX(val, delim, pos - 1)) + 1), delim, '');
IF output = '' THEN
SET output = null;
END IF;
RETURN output;
END $$
CREATE PROCEDURE TRANSFER_CELL()
BEGIN
DECLARE i INTEGER;
SET i = 1;
REPEAT
INSERT INTO products (product_id, category_id)
SELECT product_id, SPLIT_STRING(categories, ',', i)
FROM products
WHERE SPLIT_STRING(categories, ',', i) IS NOT NULL;
SET i = i + 1;
UNTIL ROW_COUNT() = 0
END REPEAT;
END $$
DELIMITER ;
CALL TRANSFER_CELL() ;
その後、すべての行を削除しますWHERE categories NOT NULL
。