首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MySQL选择相似度最大的行

问MySQL选择相似度最大的行
EN

Stack Overflow用户
提问于 2020-01-26 10:10:33
回答 3查看 80关注 0票数 0

我有一张桌子,如:

代码语言:javascript
复制
id | val1 | val2 | val3 | val4 | val5

如何找到最大计数相等的行(并非所有的值都相等)。

示例:说我在表中有4行:

代码语言:javascript
复制
1 | Mercedes | E | black | 250hp | 270kmh | 
2 | Mercedes | C | white | 250hp | 240kmh | 
3 | BMW      | C | white | 250hp | 250kmh | 
4 | PORCHE   | E | red   | 300hp | 290kmh | 

我选择:

代码语言:javascript
复制
val1=PORCHE val2=E val3=red val4=250 val5=270 

并得到:

代码语言:javascript
复制
1 | Mercedes | E | black | 250hp | 270kmh | 
4 | PORCHE   | E | red   | 300hp | 290kmh | 

因为两者都有三个相等的字段。

也不是关于汽车的问题,我希望用一张桌子来解决这个问题。

关于检查用户硬件并比较它是否绝对相等或有多少相等的表格。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-01-26 11:45:20

这是MySql 8.0+的一种解决方案,它使用rank()窗口函数返回最匹配的带有领带的行:

代码语言:javascript
复制
with cte as (
  select *,
    rank() over (order by
      (val1 = 'PORSCHE') + 
      (val2 = 'E') + 
      (val3 = 'red') + 
      (val4 = '250hp') + 
      (val5 = '270km') desc 
    ) rn
  from tablename  
) 
select * from cte
where rn = 1

见演示。

这将适用于以前的版本,但不会返回领带,这只是第一次最好的比赛:

代码语言:javascript
复制
select *
from tablename 
order by 
      (val1 = 'PORSCHE') + 
      (val2 = 'E') + 
      (val3 = 'red') + 
      (val4 = '250hp') + 
      (val5 = '270km') desc 
limit 1

见演示。

票数 0
EN

Stack Overflow用户

发布于 2020-01-26 11:13:41

我在这里用以下示例数据模型在本地重新创建了您的案例:

代码语言:javascript
复制
CREATE TABLE `cars` (
  `id` int(11) NOT NULL,
  `val1` varchar(45) DEFAULT NULL,
  `val2` varchar(45) DEFAULT NULL,
  `val3` varchar(45) DEFAULT NULL,
  `val4` varchar(45) DEFAULT NULL,
  `val5` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;


INSERT INTO `cars` (`id`, `val1`, `val2`, `val3`, `val4`, `val5`) VALUES ('1', 'Mercedes', 'E', 'black', '250hp', '270kmh');
INSERT INTO `cars` (`id`, `val1`, `val2`, `val3`, `val4`, `val5`) VALUES ('2', 'Mercedes', 'C', 'white', '250hp', '240kmh');
INSERT INTO `cars` (`id`, `val1`, `val2`, `val3`, `val4`, `val5`) VALUES ('3', 'BMW', 'C', 'white', '250hp', '250kmh');
INSERT INTO `cars` (`id`, `val1`, `val2`, `val3`, `val4`, `val5`) VALUES ('4', 'PORSCHE', 'E', 'red', '300hp', '270kmh');

为了获得你的“相似投票”,你可以这样做:

代码语言:javascript
复制
select id, count(*) as votes from
(
    select id from cars where val1 = 'PORSCHE'
    union all
    select id from cars where val2 = 'E'
    union all 
    select id from cars where val3 = 'red'
    union all
    select id from cars where val4 = '250hp'
    union all
    select id from cars where val5 = '270kmh'
) as votes
group by id

使用您的测试数据,这将生成如下内容:

代码语言:javascript
复制
id  votes
1   3
2   1
3   1
4   4

现在来了棘手的部分:我们只想要“最大的选票”(最佳匹配)。这里的挑战是,我们需要在以上两次进行此选票查询:一次提取最大值,第二次用于确定与最大票数相关的ids。如果您只想要“第一次最佳匹配”,您可以使用order by votes desc limit 1。如果您想获得“拥有最高票数的所有ids”,那么您可以这样做:

代码语言:javascript
复制
select * from (
    select id, count(*) as votes from
    (
        select id from cars where val1 = 'PORSCHE'
        union all
        select id from cars where val2 = 'E'
        union all 
        select id from cars where val3 = 'red'
        union all
        select id from cars where val4 = '250hp'
        union all
        select id from cars where val5 = '270kmh'
    ) as votes
    group by id
) hits where votes = (
    select max(votes) from (
        select id, count(*) as votes from
        (
            select id from cars where val1 = 'PORSCHE'
            union all
            select id from cars where val2 = 'E'
            union all 
            select id from cars where val3 = 'red'
            union all
            select id from cars where val4 = '250hp'
            union all
            select id from cars where val5 = '270kmh'
        ) as votes
        group by id
    ) as hits
)

不幸的是,这重复了选择查询(还需要计算两次)。关于如何在SQL只选择列上最大值的行。上最好地解决这样的问题,有大量的讨论。

在您的例子中,我还会考虑将“相似投票”写到临时表 (如果您希望比较多行的话)。这是否合适取决于应用程序具有何种类型的数据库访问。

票数 0
EN

Stack Overflow用户

发布于 2020-01-26 12:30:20

根据描述,我认为这将是最简单的解决方案:

代码语言:javascript
复制
select t.*
from (select t.*,
             rank() over (order by (t.val1 = @val1) + (t.val2 = @val2) + (t.val3 = @val3) + (t.val4 = @val4) + (t.val5 = @val5) desc) as seqnum
      from t
     ) t
where seqnum = 1;

在版本8之前的MySQL版本中,这稍微复杂一些,但没有那么糟糕:

代码语言:javascript
复制
select t.*
from t
where (t.val1 = @val1) + (t.val2 = @val2) + (t.val3 = @val3) + (t.val4 = @val4) + (t.val5 = @val5)
     ) = (select max( (t2.val1 = @val1) + (t2.val2 = @val2) + (t2.val3 = @val3) + (t2.val4 = @val4) + (t2.val5 = @val5) )
          from t t2
         );
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59917328

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档