2016-06-11 5 views
1

Я получаю ошибку «Недопустимое использование групповой функции» при выполнении этого оператора SELECT.MySQL: Nested GROUP_CONCAT

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. Также обратите внимание, что CAN может быть множеством наборов внутри ключа набора, разделенных символом ||||.

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

Пожалуйста уменьшить свой вопрос к основным компонентам запроса. –

+0

@juergend Это лучше? – forrestmid

+0

Можете ли вы сделать тест для меня, я не могу сделать от себя. Можете ли вы изменить псевдоним вашего group_concat иначе, чем имя таблицы? –

ответ

2

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

Один из возможных вариантов:

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

Я попытался выполнить и инструкцию GROUP_CONCAT (SELECT) (Возвращает «Подзапрос возвращает более 1 ошибки строки.) И SELECT GROUP_CONCAT (statement) (Возвращает ту же групповую ошибку, полученную ранее.) – forrestmid

+0

Это на самом деле очень интересно, потому что статические значения 2,3 работают в моем запросе, но когда они заменяются значениями из базы данных, это дает мне групповую ошибку. Таким образом, это действительно позволяет group_concat внутри group_concat, но я думаю, что наличие нескольких возвращаемых значений предотвращает запрос от работы. – forrestmid

+0

@forrestmid: см. обновленный ответ. – wchiquito

0

Я думаю, что проблема заключается в различиях между полями выбора и группой по полям.

это синтаксис для предложения GROUP BY в MySQL

SELECT expression1, expression2, ... expression_n, 
     aggregate_function (expression) 
FROM tables 
[WHERE conditions] 
GROUP BY expression1, expression2, ... expression_n; 

может быть, вы должны добавить только kits.is_quote к группе полей, если concat_group рассматриваются как агрегатные функции

+0

Не могли бы вы пояснить это? Я использую функцию GROUP_CONCAT, и именно это я считаю ссылкой на ошибку. После удаления GROUP BY kits.id функция возвращает ту же ошибку. – forrestmid

+0

Я не могу использовать group_concat вложенные, я ищу документацию об этом, но я еще не нашел. Но мой совет о количестве полей в группе по-прежнему остается. –

+0

Я думаю, что это возможно, потому что этот парень говорит, что он это делает, но код не придает мне смысла. https: //www.percona.com/blog/2013/10/22/the-power-of-mysql-group_concat/ – forrestmid

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) 

??

+0

Политика именования не является странной, когда вы понимаете, для чего нужен kit_id. Kit_id позволяет деталям, рабочей силе и наборам обращаться к родительскому набору. Набор kit_id в родительском наборе равен 0 или null, поэтому kit_id просто позволяет мне иметь 6 таблиц, чтобы иметь только 3, и просто не используйте kit_id, когда он мне не нужен. Запрос действителен, но со всеми псевдонимами это создавало бы проблемы. Кроме того, МОЖЕТ быть 2 или более частей, рабочей силы или комплектов для каждого родительского набора. Таким образом, может быть 5 частей, каждый с kit_id из 1 или 5 комплектов с kit_id из 1, каждый с 5 частями с kit_id каждого из наборов. – forrestmid

+0

Чтобы повторить, kit_id полностью отделен от id на каждой строке набора. Каждая строка набора имеет свой собственный уникальный идентификатор, и если это будет подкомплектом под другим комплектом, тогда kid_id будет установлен в идентификатор родительского набора, но НЕ ДОЛЖЕН быть равен его собственному уникальному идентификатору. – forrestmid

+0

Итак, в таблице наборов «kit_id» это то, что мы обычно называем «parent_id» – Strawberry

0

Это потенциальное разрешение проблемы, поэтому оно может помочь кому-то другому. Этот конкретный запрос может быть выполнен в 2 операторах SELECT, но вопрос заключается в том, чтобы сделать это в 1 инструкции SELECT, поэтому я не буду отмечать это как ответ.

Это определенно не очень хорошо, если вы хотите получить больше одного основного набора, потому что вам нужно будет сделать один запрос для списка основных наборов, а затем повторить цикл для тех основных наборов, которые делают запрос для каждого набора, чтобы получить комплекты в основном комплекте. Очень неэффективно.

Когда необходимый комплект 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;