子查询 ORDER BY 不适用于 MySQL 5.6,但适用于 5.5

Bob*_*odo 5 mysql performance order-by subquery mysql-5.6 query-performance

我尝试将 3 个表(产品、价格、类别)连接在一起,以从连接的表中获取最新和最低价格的结果。

我能够在 MySQL 5.5 上获得预期结果,但升级到 5.6 后,ORDER BY子查询似乎被忽略了。如何更改查询以使其工作ORDER BY

该查询应该是:

  1. 查找指定类别 ID 下的产品(例如:类别 ID 488)。
  2. 查找每种产品的最新价格。
  3. 将具有相同“匹配键”的产品分组(通过从产品名称中删除停用词生成的匹配键。由其他编程生成)
  4. 找到每个分组产品的最低价格
  5. 显示最低价格的每个分组产品信息

错误结果: 在此输入图像描述

3张表的关系如下:

  • 产品 <-> 多对多 <-> 类别
  • 产品 -> 一对多 -> 价格

表信息:

mysql> show columns from products;
+----------------+------------------+------+-----+---------------------+-----------------------------+
| Field          | Type             | Null | Key | Default             | Extra                       |
+----------------+------------------+------+-----+---------------------+-----------------------------+
| id             | int(10) unsigned | NO   | PRI | NULL                | auto_increment              |
| name           | varchar(300)     | NO   | MUL | NULL                |                             |
| active         | tinyint(1)       | YES  |     | 1                   |                             |
| created_at     | timestamp        | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| updated_at     | timestamp        | NO   |     | 0000-00-00 00:00:00 |                             |
| matchkey       | varchar(300)     | NO   | MUL | NULL                |                             |
| sku            | varchar(50)      | YES  | MUL | NULL                |                             |
+----------------+------------------+------+-----+---------------------+-----------------------------+

mysql> show columns from prices;
+---------------+---------------------+------+-----+---------------------+-----------------------------+
| Field         | Type                | Null | Key | Default             | Extra                       |
+---------------+---------------------+------+-----+---------------------+-----------------------------+
| id            | bigint(20) unsigned | NO   | PRI | NULL                | auto_increment              |
| price_selling | decimal(8,2)        | NO   | MUL | NULL                |                             |
| price_before  | decimal(8,2)        | NO   |     | 0.00                |                             |
| product_id    | int(10) unsigned    | NO   | MUL | NULL                |                             |
| created_at    | timestamp           | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| updated_at    | timestamp           | NO   |     | 0000-00-00 00:00:00 |                             |
+---------------+---------------------+------+-----+---------------------+-----------------------------+

mysql> show columns from categories;
+------------------+------------------+------+-----+---------------------+-----------------------------+
| Field            | Type             | Null | Key | Default             | Extra                       |
+------------------+------------------+------+-----+---------------------+-----------------------------+
| id               | int(10) unsigned | NO   | PRI | NULL                | auto_increment              |
| parent_id        | int(11)          | YES  | MUL | NULL                |                             |
| lft              | int(11)          | YES  | MUL | NULL                |                             |
| rgt              | int(11)          | YES  | MUL | NULL                |                             |
| depth            | int(11)          | YES  |     | NULL                |                             |
| name             | varchar(255)     | NO   | MUL | NULL                |                             |
| active           | tinyint(1)       | YES  |     | 1                   |                             |
| created_at       | timestamp        | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| updated_at       | timestamp        | NO   |     | 0000-00-00 00:00:00 |                             |
+------------------+------------------+------+-----+---------------------+-----------------------------+

mysql> show columns from category_product;
+--------------------+------------------+------+-----+---------+-------+
| Field              | Type             | Null | Key | Default | Extra |
+--------------------+------------------+------+-----+---------+-------+
| product_id         | int(10) unsigned | NO   | PRI | NULL    |       |
| category_id        | int(10) unsigned | NO   | PRI | NULL    |       |
+--------------------+------------------+------+-----+---------+-------+
Run Code Online (Sandbox Code Playgroud)

在 MySQL 5.5 上运行的查询是:

SELECT 
    p3.pid AS id, category_product.product_id, p3.name, p3.priceId, 
    p3.product_id, p3.price_selling, p3.price_before, MIN(p3.price_selling) AS minprice,
    p3.matchkey, categories.url_key AS category_urlkey
FROM category_product
RIGHT JOIN (
            SELECT
                pp.priceId, pp.product_id, pp.price_selling, pp.price_before,
                pp.pid, pp.name, pp.matchkey
            FROM (
                    SELECT 
                        prices.id AS priceId, prices.product_id, prices.price_selling, prices.price_before,
                        products.id AS pid, products.name, products.matchkey
                    FROM prices
                    RIGHT JOIN products ON prices.product_id = products.id
                    WHERE prices.id = (SELECT MAX(p.id) FROM prices p WHERE p.product_id = prices.product_id)
            ) AS pp
            GROUP BY pp.pid
            ORDER BY pp.price_selling ASC
            ) AS p3 ON category_product.product_id = p3.pid
RIGHT JOIN categories ON categories.id = category_product.category_id AND categories.id = 488 
GROUP BY p3.matchkey 
ORDER BY p3.pid DESC;
Run Code Online (Sandbox Code Playgroud)

表结构和示例数据可用于测试:

--
-- Table structure for table `products`
--
CREATE TABLE IF NOT EXISTS `products` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
  `active` tinyint(1) DEFAULT '1',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  `matchkey` varchar(300) COLLATE utf8_unicode_ci NOT NULL,
  `sku` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `products_sku_index` (`sku`),
  KEY `id` (`id`),
  KEY `matchkey` (`matchkey`),
  FULLTEXT KEY `name` (`name`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=60057 ;

--
-- Dumping data for table `products`
--
INSERT INTO `products` (`id`, `name`, `active`, `created_at`, `updated_at`, `matchkey`, `sku`) VALUES
(26195, 'Samsung Galaxy S3 Mini GT-I8200 Unlocked Cellphone, White, 8GB', 1, '2016-01-23 14:38:25', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(26425, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:38:28', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(26632, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:38:29', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(28212, 'Samsung Galaxy S3 Mini GT-I8200 Unlocked Cellphone, White, 8GB', 1, '2016-01-23 14:38:51', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(35111, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:39:03', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(37611, '[From U.S.A]Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:39:29', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL),
(60017, 'Samsung Galaxy S3 Mini GT-i8200 Factory Unlocked Cellphone, International Version, 8GB, White', 1, '2016-01-23 14:38:11', '0000-00-00 00:00:00', '8gb cellphone galaxy gt i8200 mini s3 samsung white', NULL);

--
-- Table structure for table `prices`
--
CREATE TABLE IF NOT EXISTS `prices` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `price_selling` decimal(8,2) NOT NULL,
  `price_before` decimal(8,2) NOT NULL DEFAULT '0.00',
  `product_id` int(10) unsigned NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `price_selling` (`price_selling`),
  KEY `id` (`id`),
  KEY `product_id` (`product_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=114663 ;

--
-- Dumping data for table `prices`
--
INSERT INTO `prices` (`id`, `price_selling`, `price_before`, `product_id`, `created_at`, `updated_at`) VALUES
(33585, '1052.40', '0.00', 26195, '2016-01-22 09:53:02', '0000-00-00 00:00:00'),
(65594, '1052.40', '0.00', 26195, '2016-01-23 01:27:08', '0000-00-00 00:00:00'),
(110038, '1052.40', '0.00', 26195, '2016-01-23 14:38:25', '0000-00-00 00:00:00'),
(33815, '1052.40', '0.00', 26425, '2016-01-22 09:55:17', '0000-00-00 00:00:00'),
(65790, '1052.40', '0.00', 26425, '2016-01-23 01:27:11', '0000-00-00 00:00:00'),
(110209, '1016.40', '0.00', 26425, '2016-01-23 14:38:28', '0000-00-00 00:00:00'),
(34022, '1052.40', '0.00', 26632, '2016-01-22 09:57:43', '0000-00-00 00:00:00'),
(66020, '1052.40', '0.00', 26632, '2016-01-23 01:27:13', '0000-00-00 00:00:00'),
(110373, '1052.40', '0.00', 26632, '2016-01-23 14:38:29', '0000-00-00 00:00:00'),
(35602, '960.25', '0.00', 28212, '2016-01-22 10:12:50', '0000-00-00 00:00:00'),
(67396, '960.25', '0.00', 28212, '2016-01-23 01:27:45', '0000-00-00 00:00:00'),
(111555, '960.25', '0.00', 28212, '2016-01-23 14:38:51', '0000-00-00 00:00:00'),
(71346, '929.20', '0.00', 35111, '2016-01-23 01:37:05', '0000-00-00 00:00:00'),
(112318, '899.30', '0.00', 35111, '2016-01-23 14:39:03', '0000-00-00 00:00:00'),
(73852, '936.10', '0.00', 37611, '2016-01-23 01:54:47', '0000-00-00 00:00:00'),
(113711, '936.10', '0.00', 37611, '2016-01-23 14:39:29', '0000-00-00 00:00:00'),
(109601, '1108.99', '2369.91', 60017, '2016-01-23 14:38:08', '0000-00-00 00:00:00');


--
-- Table structure for table `categories`
--
CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `parent_id` int(11) DEFAULT NULL,
  `lft` int(11) DEFAULT NULL,
  `rgt` int(11) DEFAULT NULL,
  `depth` int(11) DEFAULT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `url_key` varchar(200) COLLATE utf8_unicode_ci DEFAULT NULL,
  `active` tinyint(1) DEFAULT '1',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
  PRIMARY KEY (`id`),
  KEY `categories_parent_id_index` (`parent_id`),
  KEY `categories_lft_index` (`lft`),
  KEY `categories_rgt_index` (`rgt`),
  KEY `url_key` (`url_key`),
  KEY `name` (`name`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=825 ;

--
-- Dumping data for table `categories`
--
INSERT INTO `categories` (`id`, `parent_id`, `lft`, `rgt`, `depth`, `name`, `active`, `url_key`, `created_at`, `updated_at`) VALUES
(1, NULL, 1, 968, 0, 'Root', 1, NULL, '2016-01-23 13:19:51', '2016-01-23 13:19:51'),
(487, 1, 446, 453, 1, 'Mobile & Communication', 1, 'mobile-communication', '2016-01-23 13:19:51', '2016-01-23 13:19:51'),
(488, 487, 447, 448, 2, 'Mobile Phones', 1, 'mobile-phones', '2016-01-25 06:27:37', '2016-01-25 06:27:37');


--
-- Table structure for table `category_product`
--
CREATE TABLE IF NOT EXISTS `category_product` (
  `product_id` int(10) unsigned NOT NULL,
  `category_id` int(10) unsigned NOT NULL,
  PRIMARY KEY (`product_id`,`category_id`),
  KEY `product_id` (`product_id`),
  KEY `category_id` (`category_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

--
-- Dumping data for table `category_product`
--
INSERT INTO `category_product` (`product_id`, `category_id`) VALUES
(26195, 1),
(26195, 487),
(26195, 488),
(26425, 1),
(26425, 487),
(26425, 488),
(26632, 1),
(26632, 487),
(26632, 488),
(28212, 1),
(28212, 487),
(28212, 488),
(35111, 1),
(35111, 487),
(35111, 488),
(37611, 1),
(37611, 487),
(37611, 488),
(60017, 1),
(60017, 487),
(60017, 488);
Run Code Online (Sandbox Code Playgroud)

对评论的回应

如果无法解决问题,降级到 5.5 是我最后的选择。我想重写查询,我尝试更改查询仍然没有幸运地让它工作。我认为我编写的查询有问题。

对于上面提供的测试数据,查询应返回(类别 ID:488)下的产品。该查询用于价格比较网站。当用户点击网站上的类别(“手机”-数据库中的类别ID-“类别”表为488)链接时,网站将列出所有产品(按“matchkey”列分组),显示该产品的最低价格该产品组。

添加WHERE categories.id = 488categories.name = 'Mobile Phones',我仍然得到相同的结果。问题是查询结果没有显示最低价格,即使我ORDER BY pp.price_selling ASC在子查询上写入。

演示:

上面的两个演示都使用相同的查询,但结果不同。

Ric*_*mes 2

SELECT a, b ...
    GROUP BY a
Run Code Online (Sandbox Code Playgroud)

是自找麻烦。您可能在 5.5 中“幸运”,在 5.6 中“不幸”。

问题是每个“组”都可以显示的任何值。b当然,在某些情况下,给定的值a唯一地映射到给定的值b(例如,在标准化表中),但感觉与这里的情况不同。可以看到有问题:

SET sql_mode = 'ONLY_FULL_GROUP_BY';
Run Code Online (Sandbox Code Playgroud)

在执行 SELECT 之前。

另请参阅: http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sqlmode_only_full_group_by

你真的应该切换到 InnoDB。

当您到达 5.7 时,该设置将被默认启用。

分组 max 的有效技术