MySQL - 按列值获取范围内的结果
MySQL - Getting results on a range by column value
解决方案 B
因为我接受了@Strawberry 的回答,而且这个解决方案不属于 post 本身的问题,所以我不会把它写成答案,而是留给任何可能有用的人.
主要问题是查询性能和结构问题。事实上,我正在搜索所有 slides
的所有属性,然后限制结果使其变得如此缓慢。解决方案是首先获取我想要获取的幻灯片,然后从较短的结果集中搜索所有额外信息。
因此,最终查询(运行不到 0.2 秒并获得我希望的所有结果)如下:
SELECT
sl.slide_id AS slide_id,
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.title AS title,
sl.slide_type AS slide_type,
sl.report_id AS report_id,
sltg.tag_category_id AS tag_category_id,
sltg.tag_value_id AS tag_value_id,
sltgc.txt AS tag_category_text,
sltgv.txt AS tag_value_text,
FROM (SELECT
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.media_id AS media_id,
sl.title AS title,
sl.slide_type AS slide_type,
slrep.report_id AS report_id,
slrep.slide_id AS slide_id
FROM er_slides sl
INNER JOIN er_slides_in_report slrep
ON slrep.slide_id = sl.unique_id
AND slrep.report_id IN (1461317308472,1461597566425,1461598458236)
AND slrep.deleted_date IS NULL
LIMIT 0, 5
) sl
INNER JOIN er_slides_tags sltg
ON sltg.deleted_date IS NULL
AND sltg.slide_id = sl.slide_id
INNER JOIN er_slide_tags_categories sltgc
ON sltgc.id = sltg.tag_category_id
INNER JOIN er_slide_tags_values sltgv
ON sltgv.id = sltg.tag_value_id
ORDER BY slide_id, tag_value_id;
如您所见,我在搜索其他内容之前限制了集合。之后,查询运行得非常快。我希望这种方法可以帮助别人改进他们自己的查询,以我原来的查询为例,说明你不能做什么。
原题
我有一个 table,其中包含一些元素(幻灯片),这些元素在一些容器(报告)上分组,每个元素都分配有一些属性(标签值)和类别(标签类别) .它就像一个标签系统,其中元素 X 可以具有来自类别 Z 的标签 Y。
数据库结构
CREATE TABLE IF NOT EXISTS `er_reports` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`name` varchar(256) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`author` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`report_status` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'incomplete',
`num_slides` int(4) NOT NULL DEFAULT '0',
`report_type` varchar(25) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'report',
`target_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`uploaded_date` datetime DEFAULT NULL,
`deleted_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`item_reference` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_favourite` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_id` (`unique_id`),
KEY `unique_id_2` (`unique_id`),
KEY `unique_id_3` (`unique_id`),
KEY `user_id` (`user_id`),
KEY `deleted_date` (`deleted_date`),
KEY `is_favourite` (`is_favourite`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=714 ;
CREATE TABLE IF NOT EXISTS `er_slides` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`report_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`action_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`media_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`thumbnail_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`media_offset` int(6) NOT NULL DEFAULT '0',
`time_in` decimal(9,3) DEFAULT NULL,
`time_out` decimal(9,3) DEFAULT NULL,
`duration` decimal(9,3) NOT NULL DEFAULT '10.000',
`title` text COLLATE utf8_unicode_ci,
`slide_comment` text COLLATE utf8_unicode_ci,
`note_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`content` text COLLATE utf8_unicode_ci,
`media_object` text COLLATE utf8_unicode_ci,
`slide_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'action',
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_order` int(4) NOT NULL DEFAULT '0',
`count_slide` tinyint(1) NOT NULL DEFAULT '1',
`visible` tinyint(1) NOT NULL DEFAULT '1',
`deleted_date` datetime DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`uploaded_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`item_reference` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `unique_id` (`unique_id`),
KEY `report_id` (`report_id`),
KEY `deleted_date` (`deleted_date`),
KEY `action_id` (`action_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=31899 ;
CREATE TABLE IF NOT EXISTS `er_slides_in_report` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`report_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_order` int(3) NOT NULL DEFAULT '1',
`added_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`deleted_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `report_id` (`report_id`,`slide_id`,`deleted_date`),
KEY `slide_order` (`slide_order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=16843 ;
CREATE TABLE IF NOT EXISTS `er_slides_tags` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`slide_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`tag_category_id` bigint(20) NOT NULL,
`tag_value_id` bigint(20) NOT NULL,
`created_date` datetime NOT NULL,
`deleted_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `slide_id` (`slide_id`,`tag_category_id`,`tag_value_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=220623 ;
CREATE TABLE IF NOT EXISTS `er_slide_tags_categories` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`txt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `txt` (`txt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=17 ;
CREATE TABLE IF NOT EXISTS `er_slide_tags_values` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`txt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `txt` (`txt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=439 ;
我试过的
SELECT @slide_num := if(@sl_id = slrep.slide_id collate utf8_unicode_ci, @slide_num, @slide_num := @slide_num+1) as slide_num,
@sl_id := slrep.slide_id collate utf8_unicode_ci as sl_id,
slrep.report_id AS report_id,
slrep.slide_id AS slide_id,
sltg.tag_category_id AS tag_category_id,
sltg.tag_value_id AS tag_value_id,
sltgc.txt AS tag_category_text,
sltgv.txt AS tag_value_text,
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.title AS title,
sl.slide_type AS slide_type
FROM (SELECT @sl_id:=1, @slide_num := 0) v, er_slides sl
INNER JOIN er_slides_in_report slrep
ON slrep.slide_id = sl.unique_id
AND slrep.report_id IN (1461317308472,1461597566425,1461598458236)
AND slrep.deleted_date IS NULL
INNER JOIN er_slides_tags sltg
ON sltg.deleted_date IS NULL
AND sltg.slide_id = sl.unique_id
INNER JOIN er_slide_tags_categories sltgc
ON sltgc.id = sltg.tag_category_id
INNER JOIN er_slide_tags_values sltgv
ON sltgv.id = sltg.tag_value_id
WHERE @slide_num >= 0 AND @slide_num <= 5
ORDER BY slide_id, tag_value_id;
我放了一些假报告 ID 供您查看查询的构造方式。
问题
问题是这不够快 - 获取 5 张幻灯片、200 行的信息需要将近 3 秒 - 而且我无法修改 from limit。如果我写:
WHERE @slide_num >= 10 AND @slide_num <= 15
我得到一个空结果(当然,我已经检查过有足够的幻灯片)。
我也不明白为什么需要 3 秒才能得到 200 行。
我需要什么
我需要能够以最快的方式仅查询所选范围之间的那些幻灯片,这是动态的。
如果您发现缺少什么,请评论它是什么,这样我就可以 post 它。
谢谢。
编辑:解释查询(草莓方法)
正如@strawberry 所建议的,我尝试应用他的方法。但是,查询的响应时间与写入 BETWEEN 0 AND 5
的范围与写入 BETWEEN 0 AND 200
的范围相同(两者都在 17 秒左右)。
因为这可能是因为错误的索引,我决定在这里写 EXPLAIN
,因为我看不到任何错误的索引(WHERE
子句中的每个条件都有它的指数)。
考虑这个简化的例子...
DROP TABLE IF EXISTS slides;
CREATE TABLE slides
(slide_id INT NOT NULL);
INSERT INTO slides VALUES
(1),
(2),
(4),
(5),
(6),
(7);
DROP TABLE IF EXISTS slides_tags;
CREATE TABLE slides_tags
(slide_id INT NOT NULL
,tag_id INT NOT NULL
,PRIMARY KEY(slide_id,tag_id)
);
INSERT INTO slides_tags VALUES
(1,101),
(1,103),
(1,105),
(1,107),
(2,102),
(2,104),
(2,106),
(2,108),
(4,105),
(4,110),
(5,101);
SELECT slide_id
, tag_id
, i
FROM
( SELECT s.*
, st.tag_id
, CASE WHEN @prev = s.slide_id THEN @i:=@i ELSE @i:=@i+1 END i
, @prev:=s.slide_id
FROM slides s
LEFT
JOIN slides_tags st
ON st.slide_id = s.slide_id
JOIN
( SELECT @prev:=null,@i:=0) vars
ORDER
BY s.slide_id
) x
WHERE i BETWEEN 3 AND 5;
+----------+--------+------+
| slide_id | tag_id | i |
+----------+--------+------+
| 4 | 105 | 3 |
| 4 | 110 | 3 |
| 5 | 101 | 4 |
| 6 | NULL | 5 |
+----------+--------+------+
为了清楚起见,我在结果中包含了 i
列。当然,如果不需要,从超级查询中省略。
编辑:
看来您可以按如下方式重写此查询,但老实说,我对为什么这样做感到困惑:
SELECT s.slide_id
, st.tag_id
, CASE WHEN @prev = s.slide_id THEN @i:=@i ELSE @i:=@i+1 END i
, @prev:=s.slide_id
FROM (SELECT @i:=0, @prev := 0) vars
JOIN slides s
LEFT
JOIN slides_tags st
ON st.slide_id = s.slide_id
HAVING i BETWEEN 3 AND 5
ORDER
BY slide_id
, tag_id;
+----------+--------+------+-------------------+
| slide_id | tag_id | i | @prev:=s.slide_id |
+----------+--------+------+-------------------+
| 4 | 105 | 3 | 4 |
| 4 | 110 | 3 | 4 |
| 5 | 101 | 4 | 5 |
| 6 | NULL | 5 | 6 |
+----------+--------+------+-------------------+
解决方案 B
因为我接受了@Strawberry 的回答,而且这个解决方案不属于 post 本身的问题,所以我不会把它写成答案,而是留给任何可能有用的人.
主要问题是查询性能和结构问题。事实上,我正在搜索所有 slides
的所有属性,然后限制结果使其变得如此缓慢。解决方案是首先获取我想要获取的幻灯片,然后从较短的结果集中搜索所有额外信息。
因此,最终查询(运行不到 0.2 秒并获得我希望的所有结果)如下:
SELECT
sl.slide_id AS slide_id,
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.title AS title,
sl.slide_type AS slide_type,
sl.report_id AS report_id,
sltg.tag_category_id AS tag_category_id,
sltg.tag_value_id AS tag_value_id,
sltgc.txt AS tag_category_text,
sltgv.txt AS tag_value_text,
FROM (SELECT
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.media_id AS media_id,
sl.title AS title,
sl.slide_type AS slide_type,
slrep.report_id AS report_id,
slrep.slide_id AS slide_id
FROM er_slides sl
INNER JOIN er_slides_in_report slrep
ON slrep.slide_id = sl.unique_id
AND slrep.report_id IN (1461317308472,1461597566425,1461598458236)
AND slrep.deleted_date IS NULL
LIMIT 0, 5
) sl
INNER JOIN er_slides_tags sltg
ON sltg.deleted_date IS NULL
AND sltg.slide_id = sl.slide_id
INNER JOIN er_slide_tags_categories sltgc
ON sltgc.id = sltg.tag_category_id
INNER JOIN er_slide_tags_values sltgv
ON sltgv.id = sltg.tag_value_id
ORDER BY slide_id, tag_value_id;
如您所见,我在搜索其他内容之前限制了集合。之后,查询运行得非常快。我希望这种方法可以帮助别人改进他们自己的查询,以我原来的查询为例,说明你不能做什么。
原题
我有一个 table,其中包含一些元素(幻灯片),这些元素在一些容器(报告)上分组,每个元素都分配有一些属性(标签值)和类别(标签类别) .它就像一个标签系统,其中元素 X 可以具有来自类别 Z 的标签 Y。
数据库结构
CREATE TABLE IF NOT EXISTS `er_reports` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`name` varchar(256) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`author` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
`report_status` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'incomplete',
`num_slides` int(4) NOT NULL DEFAULT '0',
`report_type` varchar(25) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'report',
`target_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`uploaded_date` datetime DEFAULT NULL,
`deleted_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`item_reference` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_favourite` tinyint(4) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `unique_id` (`unique_id`),
KEY `unique_id_2` (`unique_id`),
KEY `unique_id_3` (`unique_id`),
KEY `user_id` (`user_id`),
KEY `deleted_date` (`deleted_date`),
KEY `is_favourite` (`is_favourite`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=714 ;
CREATE TABLE IF NOT EXISTS `er_slides` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`unique_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0',
`report_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`action_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`media_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`thumbnail_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`media_offset` int(6) NOT NULL DEFAULT '0',
`time_in` decimal(9,3) DEFAULT NULL,
`time_out` decimal(9,3) DEFAULT NULL,
`duration` decimal(9,3) NOT NULL DEFAULT '10.000',
`title` text COLLATE utf8_unicode_ci,
`slide_comment` text COLLATE utf8_unicode_ci,
`note_id` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
`content` text COLLATE utf8_unicode_ci,
`media_object` text COLLATE utf8_unicode_ci,
`slide_type` varchar(32) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'action',
`user_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_order` int(4) NOT NULL DEFAULT '0',
`count_slide` tinyint(1) NOT NULL DEFAULT '1',
`visible` tinyint(1) NOT NULL DEFAULT '1',
`deleted_date` datetime DEFAULT NULL,
`created_date` datetime DEFAULT NULL,
`uploaded_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`item_reference` varchar(64) COLLATE utf8_unicode_ci DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `unique_id` (`unique_id`),
KEY `report_id` (`report_id`),
KEY `deleted_date` (`deleted_date`),
KEY `action_id` (`action_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=31899 ;
CREATE TABLE IF NOT EXISTS `er_slides_in_report` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`report_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`slide_order` int(3) NOT NULL DEFAULT '1',
`added_date` datetime DEFAULT NULL,
`modified_date` datetime DEFAULT NULL,
`deleted_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `report_id` (`report_id`,`slide_id`,`deleted_date`),
KEY `slide_order` (`slide_order`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=16843 ;
CREATE TABLE IF NOT EXISTS `er_slides_tags` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`slide_id` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`tag_category_id` bigint(20) NOT NULL,
`tag_value_id` bigint(20) NOT NULL,
`created_date` datetime NOT NULL,
`deleted_date` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `slide_id` (`slide_id`,`tag_category_id`,`tag_value_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=220623 ;
CREATE TABLE IF NOT EXISTS `er_slide_tags_categories` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`txt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `txt` (`txt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=17 ;
CREATE TABLE IF NOT EXISTS `er_slide_tags_values` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`txt` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `txt` (`txt`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=439 ;
我试过的
SELECT @slide_num := if(@sl_id = slrep.slide_id collate utf8_unicode_ci, @slide_num, @slide_num := @slide_num+1) as slide_num,
@sl_id := slrep.slide_id collate utf8_unicode_ci as sl_id,
slrep.report_id AS report_id,
slrep.slide_id AS slide_id,
sltg.tag_category_id AS tag_category_id,
sltg.tag_value_id AS tag_value_id,
sltgc.txt AS tag_category_text,
sltgv.txt AS tag_value_text,
sl.time_in AS time_in,
sl.time_out AS time_out,
sl.duration AS duration,
sl.slide_order AS slide_order,
sl.title AS title,
sl.slide_type AS slide_type
FROM (SELECT @sl_id:=1, @slide_num := 0) v, er_slides sl
INNER JOIN er_slides_in_report slrep
ON slrep.slide_id = sl.unique_id
AND slrep.report_id IN (1461317308472,1461597566425,1461598458236)
AND slrep.deleted_date IS NULL
INNER JOIN er_slides_tags sltg
ON sltg.deleted_date IS NULL
AND sltg.slide_id = sl.unique_id
INNER JOIN er_slide_tags_categories sltgc
ON sltgc.id = sltg.tag_category_id
INNER JOIN er_slide_tags_values sltgv
ON sltgv.id = sltg.tag_value_id
WHERE @slide_num >= 0 AND @slide_num <= 5
ORDER BY slide_id, tag_value_id;
我放了一些假报告 ID 供您查看查询的构造方式。
问题
问题是这不够快 - 获取 5 张幻灯片、200 行的信息需要将近 3 秒 - 而且我无法修改 from limit。如果我写:
WHERE @slide_num >= 10 AND @slide_num <= 15
我得到一个空结果(当然,我已经检查过有足够的幻灯片)。
我也不明白为什么需要 3 秒才能得到 200 行。
我需要什么
我需要能够以最快的方式仅查询所选范围之间的那些幻灯片,这是动态的。
如果您发现缺少什么,请评论它是什么,这样我就可以 post 它。
谢谢。
编辑:解释查询(草莓方法)
正如@strawberry 所建议的,我尝试应用他的方法。但是,查询的响应时间与写入 BETWEEN 0 AND 5
的范围与写入 BETWEEN 0 AND 200
的范围相同(两者都在 17 秒左右)。
因为这可能是因为错误的索引,我决定在这里写 EXPLAIN
,因为我看不到任何错误的索引(WHERE
子句中的每个条件都有它的指数)。
考虑这个简化的例子...
DROP TABLE IF EXISTS slides;
CREATE TABLE slides
(slide_id INT NOT NULL);
INSERT INTO slides VALUES
(1),
(2),
(4),
(5),
(6),
(7);
DROP TABLE IF EXISTS slides_tags;
CREATE TABLE slides_tags
(slide_id INT NOT NULL
,tag_id INT NOT NULL
,PRIMARY KEY(slide_id,tag_id)
);
INSERT INTO slides_tags VALUES
(1,101),
(1,103),
(1,105),
(1,107),
(2,102),
(2,104),
(2,106),
(2,108),
(4,105),
(4,110),
(5,101);
SELECT slide_id
, tag_id
, i
FROM
( SELECT s.*
, st.tag_id
, CASE WHEN @prev = s.slide_id THEN @i:=@i ELSE @i:=@i+1 END i
, @prev:=s.slide_id
FROM slides s
LEFT
JOIN slides_tags st
ON st.slide_id = s.slide_id
JOIN
( SELECT @prev:=null,@i:=0) vars
ORDER
BY s.slide_id
) x
WHERE i BETWEEN 3 AND 5;
+----------+--------+------+
| slide_id | tag_id | i |
+----------+--------+------+
| 4 | 105 | 3 |
| 4 | 110 | 3 |
| 5 | 101 | 4 |
| 6 | NULL | 5 |
+----------+--------+------+
为了清楚起见,我在结果中包含了 i
列。当然,如果不需要,从超级查询中省略。
编辑:
看来您可以按如下方式重写此查询,但老实说,我对为什么这样做感到困惑:
SELECT s.slide_id
, st.tag_id
, CASE WHEN @prev = s.slide_id THEN @i:=@i ELSE @i:=@i+1 END i
, @prev:=s.slide_id
FROM (SELECT @i:=0, @prev := 0) vars
JOIN slides s
LEFT
JOIN slides_tags st
ON st.slide_id = s.slide_id
HAVING i BETWEEN 3 AND 5
ORDER
BY slide_id
, tag_id;
+----------+--------+------+-------------------+
| slide_id | tag_id | i | @prev:=s.slide_id |
+----------+--------+------+-------------------+
| 4 | 105 | 3 | 4 |
| 4 | 110 | 3 | 4 |
| 5 | 101 | 4 | 5 |
| 6 | NULL | 5 | 6 |
+----------+--------+------+-------------------+