Hello StackOverflow社区:

情况

我正在构建一个更新查询,根据每条记录相互比较的方式为表中的所有记录设置排名.表格示例:

id | budget | cost | rank | rank_score  
 1 |   500  |  20  |   ?  |     ?  
 2 |   400  |  40  |   ?  |     ?  
 3 |   300  |  40  |   ?  |     ?

因此,在此表中,成本在确定排名时最重要,其次是预算.因此,记录#2将排名更高,而记录#3将排名第二,#1将排在最后.如您所见,如果两条记录的成本相同,那么预算就会打破平局.


现在,为了轻松跟踪这种“权重”,我正在创建rank\_score列,它将保留成本和预算的连接.因此,上表的rank\_score将是:

id | budget | cost | rank | rank_score  
 1 |   500  |  20  |   ?  |   20500   
 2 |   400  |  40  |   ?  |   40400  
 3 |   300  |  40  |   ?  |   40300  

这个rank\_score可以填充如下:

UPDATE table_name
SET rank_score = CONCAT(cost, budget);

问题

到目前为止,一切都还好.但现在出现了问题.我需要一个仅整数的排名列,用于排序等几个东西,但最重要的是向用户显示他的记录的排名.当然,此排名列将等于rank\_scores的降序.但我找不到在单个更新查询中计算此排名列的方法,而无需执行子查询,php中的循环等.

我曾经尝试过什么

所以,起初我试图获取rank\_score计算,如:

SELECT id,
       CONCAT(cost, budget) AS rank_score
FROM table_name ;

然后在php中循环所有那些rank\_scores,只是为了构建一个类似于的查询:

UPDATE table_name
SET rank_score = CASE id WHEN 1 THEN 20500 END,
    rank = CASE id WHEN 1 THEN 3 END
WHERE id IN (1) ;

…当然,此示例更新查询未完成,因为它对表中的每条记录都有更多WHEN THEN END子句.不用说,这很难看,特别是当你期望拥有成千上万的记录时.

所以,总而言之,我已经有了计算rank\_score的方法,但我也想在同一个查询中计算排名(=排名得分的降序),或者至少没有做那个疯狂的php循环和CASE WHEN THEN END子句.

感谢您阅读和思考;)

澄清

澄清@ SJuan76所说的内容:
我无法通过php分配排名,因为有些用户将一次显示固定数量的记录(例如,他的用户页面:SELECT * WHERE user\_id = 333,可以获取1,3或8条记录)和他需要知道每条记录的排名.在这种情况下通过php分配排名不起作用,因为这样的排名将相对于获取的记录而不是表中的所有记录.

解决方法:

首先,我会将预算,成本和rank\_score更改为整数或其他数值数据类型而不是

UPDATE table_name
SET rank_score = CONCAT(cost, budget) ;

然后你会用:

UPDATE table_name
SET rank_score = cost * 1000 + budget * 1  ;

它更容易,因为你不必处理字符串函数,并有类似的东西:

SELECT * 
FROM table_name
WHERE (conditions...)
ORDER BY rank_score DESC

(括号:将一个参数(1000)设置为高于另一个(1)相当于具有成本,预算的顺序.请尝试以下方法检查:

SELECT * 
FROM table_name
ORDER BY cost DESC
       , budget DESC

因此,您可以完全放弃rank\_score,除非您当然打算使用各种参数值进行实验.

正如其他人所指出的那样,拥有一个不存储数据而是存储计算的字段并非最佳做法.这是非正常化. Instaed,您保持表的规范化,让数据库在您每次需要时进行计算:

SELECT id, budget, cost, 
       cost*1000 + budget*1 AS rank_score_calculated
FROM table_name
ORDER BY rank_score_calculated DESC

rank\_score\_calculated未存储在上面的示例中.这样,每次更改预算或成本或在表中添加新行时,您都不必更新计算字段.

只有一个缺点.如果表格非常大并且您需要经常进行大量用户的查询(和计算),并且表格经常更新,那么它可能会降低数据库的速度.在这种情况下,人们应该开始考虑添加这样的字段.

另一种情况是当需要所有表行的绝对排名时,就像你需要的那样.因为MySQL没有“窗口”功能,所以在纯SQL中编写这样的查询非常困难.)

可以使用MySQL变量计算排名

SELECT *
     , @rownum:=@rownum+1 AS rank_calculated
FROM table_name
   , (SELECT @rownum:=0) AS st
ORDER BY rank_score DESC

如果您想将这些值放入等级,请使用:

UPDATE table_name
         JOIN
         ( SELECT id
                , @rownum:=@rownum+1 AS rank_calculated
           FROM table_name
              , (SELECT @rownum:=0) AS st
           ORDER BY rank_score DESC
         ) AS r
         ON r.id = table_name.id
SET table_name.rank = r.rank_calculated ;

以上两个查询不是纯SQL.您可以检查移动到另一个支持窗口功能的daabase系统的选项,如Postgres,SQL-Server或Oracle.

标签: mysql, rank

相关文章推荐

添加新评论,含*的栏目为必填