forrestmid forrestmid - 5 months ago 34
MySQL Question

MySQL: Nested GROUP_CONCAT

I'm receiving an "Invalid use of group function" error when executing this SELECT statement.

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;


I need to be able to SELECT a kit from a database, and within that kit I need the query to return other kits, parts, and labor, with the kits part of that equation also returning parts and labor. If I remove this
GROUP_CONCAT(*) as kits
statement then the query works fine.

Upon request of the tables I'm using these are the tables with the primary info you need:

Table Creation:

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`)
)


And insert statements:

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");


Here is sample output using the above INSERT values. Also note that there CAN be multiple kits within the kits key separated by ||||.

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

Answer

Try:

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)

UPDATE

One possible option:

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)

UPDATE 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)