2009-11-28 47 views
4

好吧,让我们说,我有一个表与照片。选择一个行和周围的行

我想要做的是在页面上显示基于URI中的id的照片。贝娄照片我想要有10张附近照片的缩略图,而当前照片应该放在缩略图的中间。

这里是我的查询到目前为止(这只是一个例子,我用7号):

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 

回答

7

只有一个ORDER BY子句可以定义为UNION的查询。不要紧,如果你使用UNIONUNION ALL。 MySQL确实支持UNION的查询部分中的LIMIT子句,但是它没有定义顺序的能力是相对无用的。

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) [email protected] 

使用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 
2

我不相信你可以在UNION的不同部分有“order by”。你可能只是做这样的事情:

SELECT * FROM media where id >= 7 - 4 and id <= 7 + 4 ORDER BY id 
+2

是否有差距这将无法正常工作ID的。 – Will 2009-11-28 21:41:31

+0

噢,很好的电话,对不起。 – malonso 2009-11-29 14:57:02

1

我同意由malonso(+1)建议的答案,但如果你用ID = 1试试吧,你会得到只有5缩略图。我不知道你是否想要这种行为。如果你想永远10大拇指,你可以尝试:

select top 10 * from media where id > 7 - 4 

的问题是,选择顶级取决于数据库(在这种情况下是一个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 
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; 
1

尝试工会全部改为。 Union要求服务器确保结果是唯一的,这与您的订购冲突。

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 
0

我不得不解决类似的问题,但考虑到我们总能得到相同的行数的情况下,需要的话,即使该行已接近顶部或底部结果集(即,不完全在中间)。

该解决方案是由OMG小马响应的调整,但在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 | 
+----+