可以创建仅显示降序的mysql查询

时间:2011-07-22 22:22:16

标签: mysql sorting sql-order-by

为了开始,我想明确表示我不是按降序排序。

我希望通过其他方式进行排序,但是只有当第1列中第1列中的值小于其自身时,才会通过在第二列中显示内容来进一步过滤。一旦发现下一列较低,它就会停止。

示例:

Ordered by column-------------------Descending Column
353215                                    20
535325                                    15
523532                                    10
666464                                    30
473460                                    20

如果给出数据,我希望它只返回20,15和10.因为现在30高于10,我们不关心它下面的数据。

我到处寻找,无法找到解决方案。

6 个答案:

答案 0 :(得分:2)

你找不到解决方案,因为这是不可能的。

SQL只在一行内工作,它不能查看它上面或下面的行。

您可以编写一个存储过程来执行此操作,实际上一次循环一行并计算逻辑。

用前端语言写它可能会更容易,无论你使用什么。

答案 1 :(得分:2)

编辑:删除了大号init,并在ifnull测试中编辑了计数器,因此它适用于纯MySQL:ifnull(@prec,counter)而不是ifnull(@prec,999999)

如果您的起始表是t1且基本请求是:

select id,counter from t1 order by id;

然后使用 mysql变量,您可以完成这项工作:

SET @prec=NULL;
select * from (
    select id,counter,@prec:= if(
       ifnull(@prec,counter)>=counter,
       counter,
       -1) as prec
    from t1 order by id
 ) t2 where prec<>-1;

除了这里我需要99999作为列的最大值,并且可能有一种方法可以在第一个请求的某处将@prec的初始化设置为NULL。

这里prec列包含第一行值计数器,然后是每行的计数器值(如果它小于前一行的计数器值),并且当它变为false时为-1。

<强>更新

如果变量赋值在WHERE子句中完成,则可以完全删除外部选择:

SELECT @prec := NULL;
SELECT
  id,
  counter
FROM t1
WHERE
  (@prec := IF(
    IFNULL(@prec, counter) >= counter,
    counter,
    -1
  )) IS NOT NULL
  AND @prec <> -1
ORDER BY id;

regilero编辑: 我可以使用1行的临时表(左连接)以这种方式删除第一个初始化查询:但这可能会减慢查询速度,可能。

(...)
FROM t1 
LEFT JOIN (select @prec:=NULL as nullinit limit 1) as tmp1 ON tmp1.nullinit is null
(..)

如@Mike所说,使用简单的UNION查询甚至:

(...)
FROM t1 , (select @prec:=NULL) tmp1 
(...)
如果你想避免第一次查询,

会更好。

最后,最好的解决方案是:

SELECT NULL AS id, NULL AS counter FROM dual WHERE (@prec := NULL) 
UNION
SELECT   id,   counter
FROM t1  
WHERE   (
   @prec := IF(
      IFNULL(@prec, counter) >= counter,
      counter,
      -1   )) IS NOT NULL
AND @prec <> -1
ORDER BY id;

+--------+---------+
| id     | counter |
+--------+---------+
| 353215 |      20 |
| 523532 |      10 |
| 535325 |      15 |
+--------+---------+

EXPLAIN SELECT输出:

+----+--------------+------------+------+---------------+------+---------+------+------+------------------+
| id | select_type  | table      | type | possible_keys | key  | key_len | ref  | rows | Extra            |
+----+--------------+------------+------+---------------+------+---------+------+------+------------------+
|  1 | PRIMARY      | NULL       | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE | 
|  2 | UNION        | t1         | ALL  | NULL          | NULL | NULL    | NULL |    6 | Using where      | 
| NULL | UNION RESULT | <union1,2> | ALL  | NULL          | NULL | NULL    | NULL | NULL | Using filesort   | 
+----+--------------+------------+------+---------------+------+---------+------+------+------------------+

答案 2 :(得分:1)

我担心你不能在SQL中做到这一点。关系数据库是为不同目的而设计的,因此没有像下一行或上一行那样的抽象。用“包装”语言在SQL之外做。

答案 3 :(得分:1)

我不确定这些是否符合您的要求,但无论如何它们可能都太慢了:

SELECT t1.col1, t1.col2
  FROM tbl t1
  WHERE t1.col2 = (SELECT MIN(t2.col2) FROM tbl t2 WHERE t2.col1 <= t1.col1)

或者

SELECT t1.col1, t1.col2
  FROM tbl t1
  INNER JOIN tbl t2 ON t2.col1 <= t1.col1
  GROUP BY t1.col1, t1.col2
  HAVING t1.col2 = MIN(t2.col2)

答案 4 :(得分:0)

我猜你可以将它们(按顺序)选择到一个临时表中,它也有一个自动递增列,然后从临时表中选择,根据自动递增列(id)连接到自身,但是在t1.id = t2.id + 1的情况下,然后使用where条件(和适当的顺序by和limit 1)来查找t2中下降列大于t1的行的t1.id。之后,您可以从临时表中选择id小于或等于您刚刚找到的ID。虽然不是很漂亮! :)

答案 5 :(得分:0)

实际上可能,但性能不容易优化。如果订购Col1而Col2是降序列:

首先,您创建每行与下一行的自连接(请注意,这仅在列值唯一时有效,否则您需要连接唯一值)。

(Select Col1, (Select Min(Col2) as A2 from MyTable as B Where B.A2>A.Col1)  As Col1FromNextRow From MyTable As A) As D
INNER JOIN
(Select Col1 As C1,Col2 From MyTable As C On C.C1=D.Col1FromNextRow)

然后你实现“继续前进到第一个上升值”位:

Select Col2 FROM
(
(Select Col1, (Select Min(Col2) as A2 from MyTable as B Where B.A2>A.Col1)  As Col1FromNextRow From MyTable As A) As D
INNER JOIN
(Select Col1 As C1,Col2 From MyTable As C On C.C1=D.Col1FromNextRow)
) As E
WHERE NOT EXISTS
(SELECT Col1 FROM MyTable As Z Where z.COL1<E.Col1 and Z.Col2 < E.Col2)

我没有测试环境,所以它可能有bug。我道歉,但希望这个想法是半清晰的。

我仍然会尝试在SQL之外执行此操作。