MySQL:嵌套的GROUP_CONCAT

时间:2016-06-11 19:36:31

标签: mysql concat

我收到"无效使用群组功能"执行此SELECT语句时出错。

SELECT kits.id, kits.is_quote,
GROUP_CONCAT(
CONCAT_WS('|||', kits_table.id, kits_table.name,
    GROUP_CONCAT(
        CONCAT_WS('|', parts_table.id, parts_table.name) 
    SEPARATOR '||'),
    GROUP_CONCAT(
        CONCAT_WS('|', labor_table.id, labor_table.description) 
    SEPARATOR '||')
)
SEPARATOR '||||') as kits,
GROUP_CONCAT(CONCAT_WS('|', parts.id, parts.name) SEPARATOR '|||') as parts,
GROUP_CONCAT(CONCAT_WS('|', labor.id, labor.description) SEPARATOR '|||') as labor
FROM kits
LEFT  JOIN kits as kits_table ON kits_table.kit_id = kits.id
LEFT OUTER JOIN parts as parts_table ON parts_table.kit_id = kits_table.id
LEFT OUTER JOIN labor as labor_table ON labor_table.kit_id = kits_table.id
LEFT OUTER JOIN parts ON parts.kit_id = kits.id
LEFT OUTER JOIN labor ON labor.kit_id = kits.id
WHERE kits.id = '1'
GROUP BY kits.id;

我需要能够从数据库中选择一个工具包,并且在该工具包中我需要查询来返回其他工具包,零件和人工,其中该工具包的一部分也会返回零件和人工。如果我删除此GROUP_CONCAT(*) as kits语句,则查询工作正常。

根据表格的要求,我使用这些表格是您需要的主要信息:

表格创建:

CREATE TABLE `kits` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `kit_id` int(11) DEFAULT NULL,
  `is_quote` tinyint(4) NOT NULL DEFAULT '0',
  `name` varchar(45) DEFAULT NULL,
  `description` varchar(150) DEFAULT NULL,
  `quantity` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  KEY `KIT` (`kit_id`)
)

CREATE TABLE `labor` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `kit_id` int(11) DEFAULT NULL,
  `is_quote` tinyint(4) NOT NULL DEFAULT '0',
  `description` varchar(150) NOT NULL,
  `hours` varchar(45) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  KEY `KIT` (`kit_id`)
)

CREATE TABLE `parts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `kit_id` int(11) DEFAULT NULL,
  `is_quote` tinyint(4) NOT NULL DEFAULT '0',
  `name` varchar(45) DEFAULT NULL,
  `description` varchar(150) DEFAULT NULL,
  `sale_price` varchar(45) DEFAULT '0.00',
  `quantity` varchar(45) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_UNIQUE` (`id`),
  KEY `KIT` (`kit_id`)
)

并插入声明:

INSERT INTO `kits`
(`id`,
`kit_id`,
`is_quote`,
`name`,
`description`,
`quantity`)
VALUES
(1,0,0,"Main Kit", "Sample Description",1);

INSERT INTO `kits`
(`id`,
`kit_id`,
`is_quote`,
`name`,
`description`,
`quantity`)
VALUES
(2,1,0,"Kit within kit", "Sample Description",1);

INSERT INTO `parts`
(`kit_id`,
`is_quote`,
`name`,
`description`,
`sale_price`,
`quantity`)
VALUES
(1,0,"First Kit Part 1", "Part description","23.5",1);
 INSERT INTO `parts`
(`kit_id`,
`is_quote`,
`name`,
`description`,
`sale_price`,
`quantity`)
VALUES
(1,0,"First Kit Part 2", "Part description","23.5",1);

INSERT INTO `parts`
(`kit_id`,
`is_quote`,
`name`,
`description`,
`sale_price`,
`quantity`)
VALUES
(2,0,"Kit within kit part 1", "Sample Part Description","23.5",1);

INSERT INTO `parts`
(`kit_id`,
`is_quote`,
`name`,
`description`,
`sale_price`,
`quantity`)
VALUES
(2,0,"Kit within kit part 2", "Sample Part Description","23.5",1);

INSERT INTO `labor`
(`kit_id`,
`is_quote`,
`description`,
`hours`)
VALUES
(1,0,"First Kit labor 1","1.5");

INSERT INTO `labor`
(`kit_id`,
`is_quote`,
`description`,
`hours`)
VALUES
(1,0,"First Kit labor 2","1.5");

INSERT INTO `labor`
(`kit_id`,
`is_quote`,
`description`,
`hours`)
VALUES
(2,0,"Kit within kit labor 1","1.5");

INSERT INTO `labor`
(`kit_id`,
`is_quote`,
`description`,
`hours`)
VALUES
(2,0,"Kit within kit labor 2","1.5");

//Second Kit within kit.

INSERT INTO `kits`
(`id`,
`kit_id`,
`is_quote`,
`name`,
`description`,
`quantity`)
VALUES
(3,1,0,"Kit within kit 2", "Sample Description",1);

INSERT INTO `parts`
(`kit_id`,
`is_quote`,
`name`,
`description`,
`sale_price`,
`quantity`)
VALUES
(3,0,"Kit within kit part 1", "Sample Part Description","23.5",1);

INSERT INTO `parts`
(`kit_id`,
`is_quote`,
`name`,
`description`,
`sale_price`,
`quantity`)
VALUES
(3,0,"Kit within kit part 2", "Sample Part Description","23.5",1);

INSERT INTO `labor`
(`kit_id`,
`is_quote`,
`description`,
`hours`)
VALUES
(3,0,"Kit within kit labor 1","1.5");

INSERT INTO `labor`
(`kit_id`,
`is_quote`,
`description`,
`hours`)
VALUES
(3,0,"Kit within kit labor 2","1.5");

以下是使用上述INSERT值的示例输出。另请注意,套件密钥中可以有多个套件,由||||分隔。

+----+----------+----------------------------------------------------------------------------------------------------------------------------+------------------+-------------------+
| id | is_quote |                                                            kits                                                            |      parts       |       labor       |
+----+----------+----------------------------------------------------------------------------------------------------------------------------+------------------+-------------------+
|  1 |        0 | 2|||Kit within kit|||2|Kit within kit part 1||3|Kit within kit part 2|||2|Kit within kit labor 1||3|Kit within kit labor 2 | 1|First Kit Part | 1|First Kit labor |
+----+----------+----------------------------------------------------------------------------------------------------------------------------+------------------+-------------------+

4 个答案:

答案 0 :(得分:2)

尝试:

mysql> SELECT
    ->   GROUP_CONCAT(
    ->     CONCAT_WS('|||', 0, 1, 
    ->               GROUP_CONCAT(CONCAT_WS('|', 2, 3) SEPARATOR '||')
    ->              )
    ->             ) `test`;
ERROR 1111 (HY000): Invalid use of group function

mysql> SELECT
    ->   GROUP_CONCAT(
    ->     CONCAT_WS('|||', 0, 1, 
    ->               (SELECT GROUP_CONCAT(CONCAT_WS('|', 2, 3) SEPARATOR '||'))
    ->              )
    ->             ) `test`;
+-------------+
| test        |
+-------------+
| 0|||1|||2|3 |
+-------------+
1 row in set (0,00 sec)

<强>更新

一种可能的选择:

mysql> DROP TABLE IF EXISTS `parts`, `labor`, `kits`;
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE `kits` (
    ->   `id` int(11) NOT NULL AUTO_INCREMENT,
    ->   `kit_id` int(11) DEFAULT NULL,
    ->   `is_quote` tinyint(4) NOT NULL DEFAULT '0',
    ->   `name` varchar(45) DEFAULT NULL,
    ->   `description` varchar(150) DEFAULT NULL,
    ->   `quantity` varchar(45) DEFAULT NULL,
    ->   PRIMARY KEY (`id`),
    ->   UNIQUE KEY `id_UNIQUE` (`id`),
    ->   KEY `KIT` (`kit_id`)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE `labor` (
    ->   `id` int(11) NOT NULL AUTO_INCREMENT,
    ->   `kit_id` int(11) DEFAULT NULL,
    ->   `is_quote` tinyint(4) NOT NULL DEFAULT '0',
    ->   `description` varchar(150) NOT NULL,
    ->   `hours` varchar(45) NOT NULL DEFAULT '0',
    ->   PRIMARY KEY (`id`),
    ->   UNIQUE KEY `id_UNIQUE` (`id`),
    ->   KEY `KIT` (`kit_id`)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TABLE `parts` (
    ->   `id` int(11) NOT NULL AUTO_INCREMENT,
    ->   `kit_id` int(11) DEFAULT NULL,
    ->   `is_quote` tinyint(4) NOT NULL DEFAULT '0',
    ->   `name` varchar(45) DEFAULT NULL,
    ->   `description` varchar(150) DEFAULT NULL,
    ->   `sale_price` varchar(45) DEFAULT '0.00',
    ->   `quantity` varchar(45) NOT NULL,
    ->   PRIMARY KEY (`id`),
    ->   UNIQUE KEY `id_UNIQUE` (`id`),
    ->   KEY `KIT` (`kit_id`)
    -> );
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO `kits`
    -> (`id`,
    -> `kit_id`,
    -> `is_quote`,
    -> `name`,
    -> `description`,
    -> `quantity`)
    -> VALUES
    -> (1,0,0,"Main Kit", "Sample Description",1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `kits`
    -> (`id`,
    -> `kit_id`,
    -> `is_quote`,
    -> `name`,
    -> `description`,
    -> `quantity`)
    -> VALUES
    -> (2,1,0,"Kit within kit", "Sample Description",1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `parts`
    -> (`kit_id`,
    -> `is_quote`,
    -> `name`,
    -> `description`,
    -> `sale_price`,
    -> `quantity`)
    -> VALUES
    -> (1,0,"First Kit Part", "Part description","23.5",1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `parts`
    -> (`kit_id`,
    -> `is_quote`,
    -> `name`,
    -> `description`,
    -> `sale_price`,
    -> `quantity`)
    -> VALUES
    -> (2,0,"Kit within kit part 1", "Sample Part Description","23.5",1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `parts`
    -> (`kit_id`,
    -> `is_quote`,
    -> `name`,
    -> `description`,
    -> `sale_price`,
    -> `quantity`)
    -> VALUES
    -> (2,0,"Kit within kit part 2", "Sample Part Description","23.5",1);
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `labor`
    -> (`kit_id`,
    -> `is_quote`,
    -> `description`,
    -> `hours`)
    -> VALUES
    -> (1,0,"First Kit labor","1.5");
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `labor`
    -> (`kit_id`,
    -> `is_quote`,
    -> `description`,
    -> `hours`)
    -> VALUES
    -> (2,0,"Kit within kit labor 1","1.5");
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO `labor`
    -> (`kit_id`,
    -> `is_quote`,
    -> `description`,
    -> `hours`)
    -> VALUES
    -> (2,0,"Kit within kit labor 2","1.5");
Query OK, 1 row affected (0.00 sec)

mysql> SELECT kits.id, kits.is_quote,
    ->     GROUP_CONCAT(
    ->         CONCAT_WS('|||', kits_table.id, kits_table.name,
    ->             (SELECT GROUP_CONCAT(
    ->                 CONCAT_WS('|', parts.id, parts.name) 
    ->             SEPARATOR '||') FROM parts WHERE parts.kit_id = kits_table.id),
    ->             (SELECT GROUP_CONCAT(
    ->                 CONCAT_WS('|', labor.id, labor.description) 
    ->             SEPARATOR '||') FROM labor WHERE labor.kit_id = kits_table.id)
    ->         )
    ->     SEPARATOR '||||'
    ->     ) as kits,
    ->     GROUP_CONCAT(CONCAT_WS('|', parts.id, parts.name) SEPARATOR '|||') as parts,
    ->     GROUP_CONCAT(CONCAT_WS('|', labor.id, labor.description) SEPARATOR '|||') as labor
    -> FROM kits
    ->     LEFT JOIN kits as kits_table ON kits_table.kit_id = kits.id
    ->     LEFT OUTER JOIN parts ON parts.kit_id = kits.id
    ->     LEFT OUTER JOIN labor ON labor.kit_id = kits.id
    -> WHERE kits.id = 1
    -> GROUP BY kits.id\G
*************************** 1. row ***************************
      id: 1
is_quote: 0
    kits: 2|||Kit within kit|||2|Kit within kit part 1||3|Kit within kit part 2|||2|Kit within kit labor 1||3|Kit within kit labor 2
   parts: 1|First Kit Part
   labor: 1|First Kit labor
1 row in set (0.00 sec)

更新2

mysql> SELECT kits.id, kits.is_quote,
    ->   GROUP_CONCAT(DISTINCT
    ->       CONCAT_WS('|||', kits_table.id, kits_table.name,
    ->           (SELECT GROUP_CONCAT(DISTINCT
    ->               CONCAT_WS('|', parts.id, parts.name) 
    ->           SEPARATOR '||') FROM parts WHERE parts.kit_id = kits_table.id),
    ->           (SELECT GROUP_CONCAT(DISTINCT
    ->               CONCAT_WS('|', labor.id, labor.description) 
    ->           SEPARATOR '||') FROM labor WHERE labor.kit_id = kits_table.id)
    ->       )
    ->   SEPARATOR '||||'
    ->   ) as kits,
    ->   GROUP_CONCAT(DISTINCT CONCAT_WS('|', parts.id, parts.name) SEPARATOR '|||') as parts,
    ->   GROUP_CONCAT(DISTINCT CONCAT_WS('|', labor.id, labor.description) SEPARATOR '|||') as labor
    -> FROM kits
    ->   LEFT JOIN kits as kits_table ON kits_table.kit_id = kits.id
    ->   LEFT OUTER JOIN parts ON parts.kit_id = kits.id
    ->   LEFT OUTER JOIN labor ON labor.kit_id = kits.id
    -> WHERE kits.id = 1
    -> GROUP BY kits.id\G
*************************** 1. row ***************************
      id: 1
is_quote: 0
    kits: 2|||Kit within kit|||3|Kit within kit part 1||4|Kit within kit part 2|||3|Kit within kit labor 1||4|Kit within kit labor 2
   parts: 1|First Kit Part 1|||2|First Kit Part 2
   labor: 1|First Kit labor 1|||2|First Kit labor 2
1 row in set (0,00 sec)

答案 1 :(得分:0)

我认为问题是选择字段和逐字段之间的差异。

这是MySQL

中GROUP BY子句的语法
SELECT expression1, expression2, ... expression_n, 
       aggregate_function (expression)
FROM tables
[WHERE conditions]
GROUP BY expression1, expression2, ... expression_n;

如果将concat_group视为聚合函数,则可能只需要按字段添加kits.is_quote

答案 2 :(得分:0)

这是一个非常奇怪的命名策略 - 在名为id的表上同时包含名为kit_id的列和名为kits的列。所以,我不确定我是否做得对。所以不要介意你认为自己在寻找与否;以下是有效的查询...

SELECT k.id
     , k.name kit_name
     , k.description kit_description
     , k.quantity kit_quantity
     , p.name part_name
     , p.description part_description
     , p.sale_price part_price
     , p.quantity part_quantity
     , l.description labor_description
     , l.hours labor_hours 
  FROM kits k 
  LEFT 
  JOIN parts p 
    ON p.kit_id = k.id 
  LEFT 
  JOIN labor l 
    ON l.kit_id = k.id;

+----+----------------+--------------------+--------------+---------------------+-------------------------+------------+---------------+----------------------+-------------+
| id | kit_name       | kit_description    | kit_quantity | part_name           | part_description        | part_price | part_quantity | labor_description    | labor_hours |
+----+----------------+--------------------+--------------+---------------------+-------------------------+------------+---------------+----------------------+-------------+
|  1 | Main Kit       | Sample Description | 1            | First Kit Part      | Part description        | 23.5       | 1             | First Kit labor      | 1.5         |
|  2 | Kit within kit | Sample Description | 1            | Kit within kit part | Sample Part Description | 23.5       | 1             | Kit within kit labor | 1.5         |
+----+----------------+--------------------+--------------+---------------------+-------------------------+------------+---------------+----------------------+-------------+
2 rows in set (0.00 sec)

...

答案 3 :(得分:0)

这是该问题的潜在解决方案,因此可能对其他人有所帮助。这个特定的查询可以在2个SELECT语句中完成,但问题是要在1个SELECT语句中完成,所以我不会将其标记为答案。

如果想要获得多个主要工具包,那绝对不是好事,因为你必须对主要工具包列表提出一个请求,然后遍历那些主要工具包的for循环进行查询每个套件都可以在主套件中获得套件。非常低效。

当所需的套件ID = 1时,则:

//Fetch the main kit.
SELECT kits.id, kits.is_quote,
GROUP_CONCAT(CONCAT_WS('|', parts.id, parts.name) SEPARATOR '|||') as parts,
GROUP_CONCAT(CONCAT_WS('|', labor.id, labor.description) SEPARATOR '|||') as labor
FROM kits
LEFT OUTER JOIN parts ON parts.kit_id = kits.id
LEFT OUTER JOIN labor ON labor.kit_id = kits.id
WHERE kits.id = '1'
GROUP BY kits.id;

//Fetch an array of kits where kit_id = 1
SELECT kits.id, kits.is_quote,
GROUP_CONCAT(CONCAT_WS('|', parts.id, parts.name) SEPARATOR '|||') as parts,
GROUP_CONCAT(CONCAT_WS('|', labor.id, labor.description) SEPARATOR '|||') as labor
FROM kits
LEFT OUTER JOIN parts ON parts.kit_id = kits.id
LEFT OUTER JOIN labor ON labor.kit_id = kits.id
WHERE kits.kit_id = '1'
GROUP BY kits.id;