获取查询的列顺序

时间:2011-09-02 19:17:39

标签: mysql sql sqlite

我有一个表,其中两列[id,value]都是数字。

在这个例子中:

[ id, value ]
[ 1,  6     ]
[ 2,  4     ]
[ 3,  10    ]
[ 4,  2     ]
[ 5,  7     ]
[ 6,  3     ]

对于给定的ID,我想要检索前3个id(具有最高值的id),它们的最高位置,如果给定的id不在前3个,也得到它的位置,id和值:

示例1:ask_id = 5返回:

[ position, id, value ]
[ 1,        3,  10    ]
[ 2,        5,  7     ]
[ 3,        1,  6     ]

示例2:ask_id = 4.返回:

[ position, id, value ]
[ 1,        3,  10    ]
[ 2,        5,  7     ]
[ 3,        1,  6     ]
[ 6,        4,  2     ]

所以重点是:

  • 如何获得职位栏?
  • 如果可能的话,如何获得额外的行(无论如何,如果我需要两个查询,没有问题)?

4 个答案:

答案 0 :(得分:2)

select t2.pos, t1.id, t1.value 
from test as t1
inner join
(select id, value, @pos:=if(@pos is null, 0, @pos)+1 as pos 
 from test order by value desc) as t2
on t1.id=t2.id
where t2.pos<=3 or t2.id={$ask_id}
order by t2.pos;

答案 1 :(得分:1)

在MySQL中测试过  检索前3个id(具有最高值的id),其位置按升序排列。

set @num = 0;
SELECT @num := @num + 1 as position_sequence,id,value FROM tablename
ORDER BY value desc
limit 3;

答案 2 :(得分:1)

基本上,这个想法是这样的:

  1. value对行进行排名。

  2. 检索至少满足下列条件之一的行:

    • position BETWEEN 1 AND 3

    • id = @given_id

  3. 这些帖子举例说明了如何在MySQL中替换排名函数(至少是其中最基本的函数ROW_NUMBER()):

    这种方法应该谨慎使用,正如this article所解释的那样。

    尽管如此,上述步骤的一种可能实现可能如下所示:

    SET @pos = 0;
    
    SELECT
      position,
      id,
      value
    FROM (
      SELECT
        id,
        value,
        @pos := @pos + 1 AS position
      FROM atable
      ORDER BY value DESC
    ) s
    WHERE position BETWEEN 1 AND 3
       OR id = @given_id
    ORDER BY position
    

答案 3 :(得分:0)

我还没有(还)测试MySQL中选定答案的前三位有关系的有趣案例,但是我已经在Informix中对这些案例进行了测试,它产生了我认为应该的答案生产。

假设该表名为leader_board

CREATE TABLE leader_board(id INTEGER NOT NULL PRIMARY KEY, value INTEGER NOT NULL);
INSERT INTO leader_board(id, value) VALUES(1, 6);
INSERT INTO leader_board(id, value) VALUES(2, 4);
INSERT INTO leader_board(id, value) VALUES(3, 10);
INSERT INTO leader_board(id, value) VALUES(4, 2);
INSERT INTO leader_board(id, value) VALUES(5, 7);
INSERT INTO leader_board(id, value) VALUES(6, 3);

此查询适用于显示的数据,假设特殊ID为4:

SELECT b.position - c.tied + 1 AS standing, a.id, a.value
  FROM leader_board AS a
  JOIN (SELECT COUNT(*) AS position, d.id
          FROM leader_board AS d
          JOIN leader_board AS e ON (d.value <= e.value)
         GROUP BY d.id
       ) AS b
    ON a.id = b.id
  JOIN (SELECT COUNT(*) AS tied, f.id
          FROM leader_board AS f
          JOIN leader_board AS g ON (f.value = g.value)
         GROUP BY f.id
       ) AS c 
    ON a.id = c.id
 WHERE (a.id = 4 OR (b.position - c.tied + 1) <= 3) -- Special ID = 4; Top N = 3
 ORDER BY position, a.id;

原始数据输出:

standing        id      value

      1          3         10
      2          5          7
      3          1          6
      6          4          2

解释

这两个子查询密切相关,但它们产生不同的答案。有一段时间,我使用了两个临时表来保存这些结果。特别是,第一个子查询(AS b)产生一个位置,但是当存在联系时,该位置是最低位置而不是最高位置。那就是:

 ID     Value
  1        10
  2         7
  3         7
  4         7

输出将是:

Position   ID
  1         1
  4         2
  4         3
  4         4

但是,我们希望将它们视为:

Position   ID
  1         1
  2         2
  2         3
  2         4

因此,更正的位置是原始位置减去绑定值的数量(ID∈{2,3,4}为3,ID为1为1)加1.第二个子查询返回绑定值的数量对于每个ID。可能有一种更简洁的方法来进行计算,但我不确定它目前是什么。

特殊情况

但是,代码应该证明它处理以下情况:

  1. 有两个或多个具有相同顶值的ID值。
  2. 有两个或更多ID值具有相同的第二高分(但最高的一个是唯一的)。
  3. 有2个或更多ID值具有相同的第三高分(但前两个是唯一的)。
  4. 为了每次都保存重写查询,我将其转换为Informix样式的存储过程,该过程同时接收应显示的特殊ID和前N(默认为3)值,并将它们作为过程的参数。 (是的,RETURNING子句中的符号很奇怪。)

    CREATE PROCEDURE leader_board_standings(extra_id INTEGER, top_n INTEGER DEFAULT 3)
        RETURNING INTEGER AS standing, INTEGER AS id, INTEGER AS value;
        DEFINE standing, id, value INTEGER;
        FOREACH SELECT b.position - c.tied + 1 AS standing, a.id, a.value
                  INTO standing, id, value
                  FROM leader_board AS a
                  JOIN (SELECT COUNT(*) AS position, d.id
                          FROM leader_board AS d
                          JOIN leader_board AS e ON (d.value <= e.value)
                         GROUP BY d.id
                       ) AS b
                    ON a.id = b.id
                  JOIN (SELECT COUNT(*) AS tied, f.id
                          FROM leader_board AS f
                          JOIN leader_board AS g ON (f.value = g.value)
                         GROUP BY f.id
                       ) AS c
                    ON a.id = c.id
                 WHERE (a.id = extra_id OR (b.position - c.tied + 1) <= top_n)
                 ORDER BY position, a.id
            RETURN standing, id, value WITH RESUME;
        END FOREACH;
    END PROCEDURE;
    

    可以调用它来产生与之前相同的结果:

    EXECUTE PROCEDURE leader_board_standings(4);
    

    为了说明上面列出的各种情况,请添加和删除额外的行:

    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          3          1          6
          6          4          2
    
    INSERT INTO leader_board(id, value) VALUES(10, 10);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          1         10         10
          3          5          7
          7          4          2
    
    INSERT INTO leader_board(id, value) VALUES(11, 10);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          1         10         10
          1         11         10
          8          4          2
    
    INSERT INTO leader_board(id, value) VALUES(12, 10);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          1         10         10
          1         11         10
          1         12         10
          9          4          2
    
    DELETE FROM leader_board WHERE id IN (10, 11, 12);
    EXECUTE PROCEDURE leader_board_standings(6, 4);     -- Special ID 6; Top 4
    
          1          3         10
          2          5          7
          3          1          6
          4          2          4
          5          6          3
    
    INSERT INTO leader_board(id, value) VALUES(7, 7);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          2          7          7
          7          4          2
    
    INSERT INTO leader_board(id, value) VALUES(13, 7);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          2          7          7
          2         13          7
          8          4          2
    
    INSERT INTO leader_board(id, value) VALUES(14, 7);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          2          7          7
          2         13          7
          2         14          7
          9          4          2
    
    DELETE FROM leader_board WHERE id IN(7, 13, 14);
    INSERT INTO leader_board(id, value) VALUES(8, 6);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          3          1          6
          3          8          6
          7          4          2
    
    INSERT INTO leader_board(id, value) VALUES(9, 6);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          3          1          6
          3          8          6
          3          9          6
          8          4          2
    
    INSERT INTO leader_board(id, value) VALUES(15, 6);
    EXECUTE PROCEDURE leader_board_standings(4);
    
          1          3         10
          2          5          7
          3          1          6
          3          8          6
          3          9          6
          3         15          6
          9          4          2
    
    EXECUTE PROCEDURE leader_board_standings(3);  -- Special ID 3 appears in top 3
    
          1          3         10
          2          5          7
          3          1          6
    

    这一切对我来说都是正确的。