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