我有UNION ALL
加入的两个select语句。在第一个语句中,where子句仅收集先前向用户显示的行。第二个语句收集所有未向用户显示的行,因此我最终得到的结果是查看结果,之后是未查看结果。
当然这可以通过使用简单ORDER BY
的相同select语句来实现,但是在您意识到我希望实现的目标之后,两个单独选择的原因很简单。
考虑以下结构和数据。
+----+------+-----+--------+------+
| id | from | to | viewed | data |
+----+------+-----+--------+------+
| 1 | 1 | 10 | true | .... |
| 2 | 10 | 1 | true | .... |
| 3 | 1 | 10 | true | .... |
| 4 | 6 | 8 | true | .... |
| 5 | 1 | 10 | true | .... |
| 6 | 10 | 1 | true | .... |
| 7 | 8 | 6 | true | .... |
| 8 | 10 | 1 | true | .... |
| 9 | 6 | 8 | true | .... |
| 10 | 2 | 3 | true | .... |
| 11 | 1 | 10 | true | .... |
| 12 | 8 | 6 | true | .... |
| 13 | 10 | 1 | false | .... |
| 14 | 1 | 10 | false | .... |
| 15 | 6 | 8 | false | .... |
| 16 | 10 | 1 | false | .... |
| 17 | 8 | 6 | false | .... |
| 18 | 3 | 2 | false | .... |
+----+------+-----+--------+------+
基本上我希望语句选择所有未查看的行,这是通过检查viewed
列true
列为false
或viewed is TRUE
的天气来完成的,非常简单明了,没有任何内容担心在这里。
但是,对于已经查看过的行,意为列+----+------+-----+--------+------+
| id | from | to | viewed | data |
+----+------+-----+--------+------+
| 6 | 10 | 1 | true | .... |
| 7 | 8 | 6 | true | .... |
| 8 | 10 | 1 | true | .... |
| 9 | 6 | 8 | true | .... |
| 10 | 2 | 3 | true | .... |
| 11 | 1 | 10 | true | .... |
| 12 | 8 | 6 | true | .... |
+----+------+-----+--------+------+
,对于这些记录,我只想为每个组返回3行。
此实例中的相应结果应为每组中最近的3行。
from = x
从理想的结果集中可以看出,我们有三组。因此,查看结果的所需查询应为其找到的每个分组显示最多3行。在这种情况下,这些分组为10,其中1为1,8为6,两个都有三行显示,而另一组3只有3,只有一行显示。
请注意,在to = y
和from = y
的位置,进行相同的分组,就好像to = x
和from = 10
一样。因此,考虑到第一个分组(10个为1),to = 1
和from = 1
如果是to = 10
和id
则属于同一组。
但是整个表中有很多组我只希望在select语句中返回最近的3个组,这就是我的问题,我不知道如何以最有效的方式完成考虑到这个表在某些时候会有数百条甚至数千条记录。
感谢您的帮助。
注意:列from
,to
,viewed
和{{1}}已编入索引,这有助于提升效果。
PS:我不确定如何准确地命名这个问题,如果你有更好的主意,请成为我的客人并编辑标题。
答案 0 :(得分:3)
真是个毛球!随着您从最近的,最近的第二次到最近的第三次,这种情况越来越难。
让我们通过获取我们需要的ID列表将它们放在一起。然后我们可以通过ID从表中提取项目。
这个相对简单的查询可以获得最新项目的ID
SELECT id FROM
(SELECT max(id) id, fromitem, toitem
FROM stuff
WHERE viewed = 'true'
GROUP BY fromitem, toitem
)a
小提琴:http://sqlfiddle.com/#!2/f7045/27/0
接下来,我们需要获取第二个最新项目的ID。为此,我们需要一个自联接样式查询。我们需要做同样的摘要,但是在省略最新项目的虚拟表上。
select id from (
select max(b.id) id, b.fromitem, b.toitem
from stuff a
join
(select id, fromitem, toitem
from stuff
where viewed = 'true'
) b on ( a.fromitem = b.fromitem
and a.toitem = b.toitem
and b.id < a.id)
where a.viewed = 'true'
group by fromitem, toitem
)c
小提琴:http://sqlfiddle.com/#!2/f7045/44/0
最后,我们需要获取第三个最新项目的ID。怜悯!我们需要将我们刚才的查询加入到表中。
select id from
(
select max(d.id) id, d.fromitem, d.toitem
from stuff d
join
(
select max(b.id) id, b.fromitem, b.toitem
from stuff a
join
(
select id, fromitem, toitem
from stuff
where viewed = 'true'
) b on ( a.fromitem = b.fromitem
and a.toitem = b.toitem
and b.id < a.id)
where a.viewed = 'true'
group by fromitem, toitem
) c on ( d.fromitem = c.fromitem
and d.toitem = c.toitem
and d.id < c.id)
where d.viewed='true'
group by d.fromitem, d.toitem
) e
小提琴:http://sqlfiddle.com/#!2/f7045/45/0
所以,现在我们采用所有这些id的联合,并使用它们从表中抓取正确的行,我们就完成了。
SELECT *
FROM STUFF
WHERE ID IN
(
SELECT id FROM
(SELECT max(id) id, fromitem, toitem
FROM stuff
WHERE viewed = 'true'
GROUP BY fromitem, toitem
)a
UNION
select id from (
select max(b.id) id, b.fromitem, b.toitem
from stuff a
join
(select id, fromitem, toitem
from stuff
where viewed = 'true'
) b on ( a.fromitem = b.fromitem
and a.toitem = b.toitem
and b.id < a.id)
where a.viewed = 'true'
group by fromitem, toitem
)c
UNION
select id from
(
select max(d.id) id, d.fromitem, d.toitem
from stuff d
join
(
select max(b.id) id, b.fromitem, b.toitem
from stuff a
join
(
select id, fromitem, toitem
from stuff
where viewed = 'true'
) b on ( a.fromitem = b.fromitem
and a.toitem = b.toitem
and b.id < a.id)
where a.viewed = 'true'
group by fromitem, toitem
) c on ( d.fromitem = c.fromitem
and d.toitem = c.toitem
and d.id < c.id)
where d.viewed='true'
group by d.fromitem, d.toitem
) e
UNION
select id from stuff where viewed='false'
)
order by viewed desc, fromitem, toitem, id desc
嘻嘻。 SQL太多了。小提琴:http://sqlfiddle.com/#!2/f7045/47/0
现在,我们需要应对您的上一个要求,即图表无序的要求。也就是说,from = n到= m与from = m到= n相同。
为此,我们需要一个虚拟表而不是物理表。这样就可以了。
SELECT id, least(fromitem, toitem) fromitem, greatest(fromitem,toitem) toitem, data
FROM stuff
现在我们需要使用这个虚拟表,这个视图,到处都是物理表出现的地方。让我们使用一个视图来做到这一点。
CREATE VIEW
AS
SELECT id,
LEAST(fromitem, toitem) fromitem,
GREATEST (fromitem, toitem) toitem,
viewed,
data;
所以,我们的最终查询是:
SELECT *
FROM stuff
WHERE ID IN
(
SELECT id FROM
(SELECT max(id) id, fromitem, toitem
FROM STUFF_UNORDERED
WHERE viewed = 'true'
GROUP BY fromitem, toitem
)a
UNION
SELECT id FROM (
SELECT max(b.id) id, b.fromitem, b.toitem
FROM STUFF_UNORDERED a
JOIN
(SELECT id, fromitem, toitem
FROM STUFF_UNORDERED
WHERE viewed = 'true'
) b ON ( a.fromitem = b.fromitem
AND a.toitem = b.toitem
AND b.id < a.id)
WHERE a.viewed = 'true'
GROUP BY fromitem, toitem
)c
UNION
SELECT id FROM
(
SELECT max(d.id) id, d.fromitem, d.toitem
FROM STUFF_UNORDERED d
JOIN
(
SELECT max(b.id) id, b.fromitem, b.toitem
FROM STUFF_UNORDERED a
JOIN
(
SELECT id, fromitem, toitem
FROM STUFF_UNORDERED
WHERE viewed = 'true'
) b ON ( a.fromitem = b.fromitem
AND a.toitem = b.toitem
AND b.id < a.id)
WHERE a.viewed = 'true'
GROUP BY fromitem, toitem
) c ON ( d.fromitem = c.fromitem
AND d.toitem = c.toitem
AND d.id < c.id)
WHERE d.viewed='true'
GROUP BY d.fromitem, d.toitem
) e
UNION
SELECT id FROM STUFF_UNORDERED WHERE viewed='false'
)
ORDER BY viewed DESC,
least(fromitem, toitem),
greatest(fromitem, toitem),
id DESC