按列排序表并获取行号

Posted

技术标签:

【中文标题】按列排序表并获取行号【英文标题】:Order table by column and get row number 【发布时间】:2021-07-14 08:27:02 【问题描述】:

在我的数据库中,我有表wp_postmeta,例如:

| meta_key | meta_value |  post_id   |
---------------------------------
   points  |     12     |  23
   points  |     2      |  18
   lorem   |     ipsum  |  92
   points  |     8      |  15

我想通过meta_value 订购points 并获取特定post_id 的行号。基本上是一个排名系统,最高的数字在顶部。

例如,通过meta_value 订购points

| meta_key | meta_value |  post_id   |
---------------------------------
   points  |     12     |  23
   points  |     8      |  15
   points  |     2      |  18

因此,post_id 的值为 15 将是排名 2

我可以使用什么 SQL 查询来实现这个优化?

到目前为止我尝试过的内容

到目前为止,我已经通过查询实现了这一点:

$query="
    SELECT post_id,FIND_IN_SET(
                  post_id,(SELECT GROUP_CONCAT( post_id ORDER BY meta_value * 1 DESC)
                          FROM $wpdb->postmeta
                          WHERE meta_key ='points')
                       ) AS `rank`
    FROM $wpdb->postmeta
    WHERE meta_key ='points'
    AND post_id = '".$post_id."'
    ";

$result  = $wpdb->get_row($query);

$rank = $result->rank;

工作正常。 但是,这个查询很慢。

我怎样才能使这个查询更快?

编辑:这是该表中的索引列表:

【问题讨论】:

我到目前为止所尝试的应该是这个平台上的一个标准。 +1 这个问题符合条件的时候我会奖励50分。 你的mysql是什么版本的? @forpas 最新版本。 MySQL 8. @forpas 你能用我的代码作为参考,用这种方法发布答案吗? 【参考方案1】:

使用ROW_NUMBER()(或RANK(),如果有联系)窗口函数:

SELECT *, ROW_NUMBER() OVER (ORDER BY meta_value + 0 DESC) `rank` 
FROM wp_postmeta 
WHERE meta_key = 'points' 
ORDER BY `rank`

如果你想要特定post_id的等级:

SELECT *
FROM (
  SELECT *, ROW_NUMBER() OVER (ORDER BY meta_value + 0 DESC) `rank` 
  FROM wp_postmeta 
  WHERE meta_key = 'points' 
) t
WHERE post_id = '15';

或者:

SELECT *, ROW_NUMBER() OVER (ORDER BY meta_value + 0 DESC) `rank` 
FROM wp_postmeta 
WHERE meta_key = 'points' 
ORDER BY post_id = '15' DESC LIMIT 1;

【讨论】:

@HenrikPetterson 你的意思是你只想要 post_id = 15 的排名吗? 是的,完全正确。我想知道 post_id = 15 的排名(或者基本上是针对一个特定 post_id 的能力)... 我对这个和我原来的方法进行了速度测试,不幸的是几乎没有任何区别。有没有一种方法可以使查询执行得更快,这是我最初的问题?谢谢。 这是这个特定表的索引设置:i.imgur.com/QReQbZj.png @HenrikPetterson 我认为除了窗口函数之外没有任何方法来获得排名位置会更好。您的实际问题是 meta_value 必须转换为 ROW_NUMBER() 的 ORDER BY 子句中的数字。这使得meta_value 上的索引毫无用处。【参考方案2】:

如果meta_value 存储为数字,则以下方法可能是最快的方法:

select count(*) + 1
from wp_postmeta pm
where pm.meta_key = 'points' and
      pm.meta_value > (select pm2.meta_value
                       from wp_postmeta pm2
                       where pm2.meta_key = 'points' and
                             pm2.post_id = 15
                      );

这可以利用wp_postmeta(meta_key, post_id, meta_value)wp_postmeta(meta_key, meta_value) 上的索引。

但是,meta_value 可能是一个字符串,因此 > 比较不起作用。一种选择是生成列,将值转换为数字。我不确定是否要修改数据模型。

目标是避免按非索引键排序。另一种方法做类似的事情,但像这样:

select count(*) + 1
from wp_postmeta pm cross join
     (select pm2.meta_value
      from wp_postmeta pm2
      where pm2.meta_key = 'points' and
            pm2.post_id = 15
     ) pm2
where pm.meta_key = 'points' and
      (pm.meta_value + 0) > (pm2.meta_value + 0);

wp_postmeta(meta_key, post_id, meta_value) 上有一个索引。这应该是对pm2 的索引查找,然后是对外部查询的points 记录的索引扫描。

【讨论】:

我测试了这两个例子。你是对的,meta_value 是一个字符串,所以第一个代码不起作用。第二个做了,但它比我的问题中发布的查询快一点。是否可以在查询中将meta_value 转换为int 而不是调整数据库结构?鉴于这是一个 WordPress 平台,调整数据库索引结构可能并不有利。那么考虑到这一点,我是否没有可行的选择?顺便说一句,恒星的答案。编辑:表索引设置:i.stack.imgur.com/r8CXs.png @HenrikPetterson 。 . .第一个版本可能不会返回正确的结果,但它有多快? 第一个版本比第二个版本稍 @HenrikPetterson 。 . .有趣的。我想知道这是否是由于字符串比较(即使是非常短的字符串)比整数比较更复杂。【参考方案3】:
SELECT * FROM wp_postmeta WHERE meta_key = 'points' ORDER BY meta_value+0 DESC

对于这个问题的其余部分,一个简单的 php 就足够了:

<?php

/*
DROP TABLE IF EXISTS wp_postmeta;

CREATE TABLE wp_postmeta
(meta_key VARCHAR(12) NOT NULL
,meta_value VARCHAR(12) NOT NULL
,post_id INT NOT NULL PRIMARY KEY
,UNIQUE KEY(meta_key,meta_value)
);

INSERT INTO wp_postmeta VALUES
('points','12',23),
('points','2',18),
('lorem','ipsum',92),
('points','8',15);
*/

  require('path/to/pdo/connection/stateme.nts');
  $query = "SELECT post_id FROM wp_postmeta WHERE meta_key = 'points' ORDER BY meta_value+0 DESC";
  $data = $pdo->query($query)->fetchAll(PDO::FETCH_COLUMN, 0);


echo array_search('15',$data)+1;

?>

输出:2

【讨论】:

如何:它更快,因为它比您的查询花费的时间更少。为什么:因为它没有不能使用索引和子查询的不必要的功能。 请查看我更新的问题。已编辑:“我想通过meta_value 订购points 并获取特定post_id 的行号。” 太棒了。这就是上面的查询所做的。 但是如何将post_id 定位为15

以上是关于按列排序表并获取行号的主要内容,如果未能解决你的问题,请参考以下文章

MATLAB 常用数据处理命令

按列和值比较两个 csv 文件并显示不同值的行号 [关闭]

如何按列对多维数组进行排序?

按列对csv进行排序

Pandas Dataframe 按列排序[重复]

CrudRepository:返回一个结果,按列排序[重复]