3つのテーブル(製品、価格、カテゴリ)を結合して、結合したテーブルから最新&最低価格の結果を取得しようとします。
MySQL 5.5で期待どおりの結果を得ることができましたが、5.6にアップグレードした後、サブクエリのORDER BY
は無視されるようです。 ORDER BY
を機能させるためにクエリを変更する方法は?
クエリは次のように想定されています。
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 | |
+--------------------+------------------+------+-----+---------+-------+
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;
テーブル構造とサンプルデータをテストに使用できます。
--
-- 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);
5.5にダウングレードすることは、それを修正できない場合の私の最後のオプションです。クエリを書き直したいのですが、クエリを変更してみましたが、うまくいきませんでした。私が書くクエリに何か問題があると思います。
上記のテストデータの場合、クエリは(カテゴリID:488)の製品を返す必要があります。クエリは価格比較サイトに使用されます。ユーザーがWebサイトのカテゴリー(「携帯電話」-データベースのカテゴリーID-「カテゴリー」テーブルは488)リンクをクリックすると、Webサイトはすべての製品(「matchkey」列でグループ化)をリストし、その製品グループ。
WHERE categories.id = 488
またはcategories.name = 'Mobile Phones'
を追加しても、同じ結果が得られます。問題は、サブクエリにORDER BY pp.price_selling ASC
と書いても、クエリ結果に最低価格が表示されないことです。
デモ:
上記の両方のデモは同じクエリを使用していますが、結果は異なります。
SELECT a, b ...
GROUP BY a
トラブルを求めています。 5.5では「ラッキー」、5.6では「アンラッキー」でした。
問題は、anyb
の値が「グループ」ごとに表示できることです。確かに、特定のa
が特定のb
に一意にマップされる場合があります(たとえば、正規化テーブル内)。しかし、ここではそうではありません。問題があることを確認するには:
SET sql_mode = 'ONLY_FULL_GROUP_BY';
sELECTを実行する前に。
参照: http://dev.mysql.com/doc/refman/5.6/en/sql-mode.html#sqlmode_only_full_group_by
本当にInnoDBに切り替えるべきです。
5.7に到達すると、その設定がデフォルトでオンになります。