好吧,假设我有一张带照片的桌子。
我想要做的是在页面上根据URI中的id显示照片。对照片感兴趣我希望有10张附近照片的缩略图,当前的照片应该在缩略图的中间。
这是我到目前为止的查询(这只是一个例子,我用7作为id):
SELECT
A.*
FROM
(SELECT
*
FROM media
WHERE id < 7
ORDER BY id DESC
LIMIT 0, 4
UNION
SELECT
*
FROM media
WHERE id >= 7
ORDER BY id ASC
LIMIT 0, 6
) as A
ORDER BY A.id
但是我收到了这个错误:
#1221 - Incorrect usage of UNION and ORDER BY
答案 0 :(得分:7)
只能为ORDER BY
'd查询定义一个UNION
子句。使用UNION
或UNION ALL
无关紧要。 MySQL确实支持LIMIT
d查询部分的UNION
子句,但如果没有定义顺序的能力则相对无用。
MySQL还缺少排名功能,您需要处理数据中的空白(由于条目被删除而丢失)。唯一的选择是在SELECT语句中使用递增变量:
SELECT t.id,
@rownum := @rownum+1 as rownum
FROM MEDIA t, (SELECT @rownum := 0) r
现在我们可以获得连续编号的行列表,因此我们可以使用:
WHERE rownum BETWEEN @midpoint - ROUND(@midpoint/2)
AND @midpoint - ROUND(@midpoint/2) +@upperlimit
使用7作为@midpoint的值,@midpoint - ROUND(@midpoint/2)
返回值4
。要获得总共10行,请将@upperlimit值设置为10.这是完整查询:
SELECT x.*
FROM (SELECT t.id,
@rownum := @rownum+1 as rownum
FROM MEDIA t,
(SELECT @rownum := 0) r) x
WHERE x.rownum BETWEEN @midpoint - ROUND(@midpoint/2) AND @midpoint - ROUND(@midpoint/2) + @upperlimit
但如果您仍想使用LIMIT
,则可以使用:
SELECT x.*
FROM (SELECT t.id,
@rownum := @rownum+1 as rownum
FROM MEDIA t,
(SELECT @rownum := 0) r) x
WHERE x.rownum >= @midpoint - ROUND(@midpoint/2)
ORDER BY x.id ASC
LIMIT 10
答案 1 :(得分:4)
我使用以下代码解决了这个问题:
SELECT A.* FROM (
(
SELECT * FROM gossips
WHERE id < 7
ORDER BY id DESC
LIMIT 2
)
UNION
(
SELECT * FROM gossips
WHERE id > 7
ORDER BY id ASC
LIMIT 2
)
) as A
ORDER BY A.id
答案 2 :(得分:2)
我不相信你可以在UNION的不同部分拥有“order by”。你能做这样的事吗:
SELECT * FROM media where id >= 7 - 4 and id <= 7 + 4 ORDER BY id
答案 3 :(得分:1)
我同意malonso(+1)提出的答案,但如果你尝试使用id = 1,你将只获得5个缩略图。我不知道你是否想要这种行为。如果你想要总是10个拇指,你可以尝试:
select top 10 * from media where id > 7 - 4
问题是select top与数据库有关(在本例中是sql server子句)。其他数据库也有类似的条款:
甲骨文:
SELECT * media
FROM media
WHERE ROWNUM < 10
AND id > 7 - 4
MySQL的:
SELECT *
FROM media
WHERE id > 7 - 4
LIMIT 10
所以也许你可以使用最后一个。
如果我们这样做,如果你想要最后10个拇指,我们会遇到同样的问题。例如,如果我们有90个拇指,我们给出一个id = 88 ...你可以解决它添加OR条件。在MySQL中将是:
SELECT *
FROM media
WHERE id > 7 - 4
OR (Id+5) > (select COUNT(1) from media)
LIMIT 10
答案 4 :(得分:1)
如果您愿意使用临时表,可以细分原始查询以使用它们。
SELECT
*
FROM media
WHERE id < 7
ORDER BY id DESC
LIMIT 0, 4
INTO TEMP t1;
INSERT INTO t1
SELECT
*
FROM media
WHERE id >= 7
ORDER BY id ASC
LIMIT 0, 6;
select * from t1 order by id;
drop table t1;
答案 5 :(得分:1)
尝试 union all 。 Union要求服务器确保结果是唯一的,这与您的订购相冲突。
答案 6 :(得分:0)
我必须解决类似的问题,但需要考虑我们总是得到相同行数的情况,即使所需的行靠近结果集的顶部或底部(即不完全在中间)。
这个解决方案是OMG小马的一个调整&#39;响应,但rownum在所需的行最大值:
set @id = 7;
SELECT natSorted.id
FROM (
SELECT gravitySorted.* FROM (
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
) AS gravitySorted ORDER BY gravity DESC LIMIT 10
) natSorted ORDER BY id;
这是对发生的事情的分解:
注意:在下面的示例中,我创建了一个包含20行的表,并删除了ID 6和9,以确保ID中的间隙不会影响结果
首先,我们为每一行分配一个重力值,该重力值以您正在寻找的特定行为中心(在这种情况下,id为7)。该行越靠近所需的行,该值就越高:
SET @id = 7;
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
返回:
+----+---------+
| id | gravity |
+----+---------+
| 1 | 1 |
| 2 | 2 |
| 3 | 3 |
| 4 | 4 |
| 5 | 5 |
| 7 | 6 |
| 8 | 5 |
| 10 | 4 |
| 11 | 3 |
| 12 | 2 |
| 13 | 1 |
| 14 | 0 |
| 15 | -1 |
| 16 | -2 |
| 17 | -3 |
| 18 | -4 |
| 19 | -5 |
| 20 | -6 |
| 21 | -7 |
+----+---------+
接下来,我们按重力值排序所有结果并限制所需的行数:
SET @id = 7;
SELECT gravitySorted.* FROM (
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
) AS gravitySorted ORDER BY gravity DESC LIMIT 10
返回:
+----+---------+
| id | gravity |
+----+---------+
| 7 | 6 |
| 5 | 5 |
| 8 | 5 |
| 4 | 4 |
| 10 | 4 |
| 3 | 3 |
| 11 | 3 |
| 2 | 2 |
| 12 | 2 |
| 1 | 1 |
+----+---------+
此时我们拥有所有想要的ID,我们只需要将它们排序回原来的顺序:
set @id = 7;
SELECT natSorted.id
FROM (
SELECT gravitySorted.* FROM (
SELECT Media.id, IF(id <= @id, @gravity := @gravity + 1, @gravity := @gravity - 1) AS gravity
FROM Media, (SELECT @gravity := 0) g
) AS gravitySorted ORDER BY gravity DESC LIMIT 10
) natSorted ORDER BY id;
返回:
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 7 |
| 8 |
| 10 |
| 11 |
| 12 |
+----+