MySQL:嵌套 GROUP_CONCAT

MySQL: Nested GROUP_CONCAT

我在执行此 SELECT 语句时收到 "Invalid use of group function" 错误。

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;

我需要能够从数据库中 SELECT 一个工具包,并且在该工具包中我需要查询 return 其他工具包、零件和人工,以及其中的工具包方程还 return 零件和人工。如果我删除此 GROUP_CONCAT(*) as kits 语句,则查询工作正常。

根据我正在使用的表格的要求,这些表格包含您需要的主要信息:

Table 创建:

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 |
+----+----------+----------------------------------------------------------------------------------------------------------------------------+------------------+-------------------+

我认为问题是 select 字段和按字段分组之间的差异。

这是 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 添加到分组字段中

尝试:

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)

这是一个非常奇怪的命名策略 - 在名为 kits 的 table 上同时具有一个名为 id 的列和一个名为 kit_id 的列。所以,我不确定我是否做对了。因此,不要介意它是否是您认为正在寻找的东西;以下是有效查询吗...

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)

??

这是问题的潜在解决方案,因此可能会对其他人有所帮助。这个特定的查询可以在 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;