Mysql 在多列中统计匹配项

Mysql 在多列中统计匹配项,mysql,Mysql,让我们有一个有五列的表。每列(num1,num2,…num5)按升序保存一个从1到90的唯一数字。(因此最低的数字在num1中,最高的数字在num5中)用户提示五个数字(val1,val2,…val5),它们在到达数据库之前由程序按升序排序 任务是统计表中有多少记录与用户给定的五个数字中的五个、四个、三个和两个匹配 计算五个匹配项很容易,因为数字的顺序相同,所以我不必处理排列 SELECT count(*) FROM table WHERE num1 = val1 AND num2 = val2

让我们有一个有五列的表。每列(
num1
num2
,…
num5
)按升序保存一个从1到90的唯一数字。(因此最低的数字在
num1
中,最高的数字在
num5
中)用户提示五个数字(
val1
val2
,…
val5
),它们在到达数据库之前由程序按升序排序

任务是统计表中有多少记录与用户给定的五个数字中的五个、四个、三个和两个匹配

计算五个匹配项很容易,因为数字的顺序相同,所以我不必处理排列

SELECT count(*) FROM table
WHERE num1 = val1 AND num2 = val2 AND num3 = val3 AND num4 = val4 AND num5 = val5
问题是,我不知道如何开始计算四场、三场和两场比赛。 我不知道SQL是否能够完成这样的任务

为了简单起见,我们只处理这四个匹配项。五个数字中哪四个匹配并不重要,但例如
num5
可以匹配
val4
val5
,这使得匹配更加复杂


那么,有什么提示可以解决这个问题吗?如果需要,我可以重新构造表,但我必须使用MySQL。

MySQL将布尔表达式计算为1或0,因此您可以这样使用它们:

create table tablename(num1 int, num2 int, num3 int, num4 int, num5 int);
insert into tablename(num1, num2, num3, num4, num5) values
(1, 2, 3, 4, 5),
(1, 5, 10, 11, 85),
(1, 17, 23, 34, 45),
(1, 2, 3, 4, 6),
(1, 2, 3, 4, 7),
(1, 20, 30, 40, 50),
(1, 22, 32, 42, 55),
(1, 2, 3, 4, 5),
(10, 20, 30, 40, 50);

SET @val1 = 1;
SET @val2 = 2;
SET @val3 = 3;
SET @val4 = 4;
SET @val5 = 5;
SELECT t.matches, count(*) counter
FROM (
  SELECT 
    (num1 in (@val1, @val2, @val3, @val4, @val5)) + 
    (num2 in (@val1, @val2, @val3, @val4, @val5)) + 
    (num3 in (@val1, @val2, @val3, @val4, @val5)) + 
    (num4 in (@val1, @val2, @val3, @val4, @val5)) + 
    (num5 in (@val1, @val2, @val3, @val4, @val5)) matches
  FROM tablename
) t
GROUP BY t.matches
ORDER BY t.matches DESC 
子查询的每一行将包含列值和5个数字之间的匹配数。
因此,您可以根据此结果进行分组并统计每个案例。
请参阅。
对于Mysql 8.0+您可以使用CTE:

SET @val1 = 1;
SET @val2 = 2;
SET @val3 = 3;
SET @val4 = 4;
SET @val5 = 5;
WITH cte as (
  SELECT @val1 val UNION ALL SELECT @val2 UNION ALL  
  SELECT @val3 UNION ALL SELECT @val4 UNION ALL SELECT @val5
)  
SELECT t.matches, count(*) counter
FROM (
  SELECT 
    (num1 in (SELECT val FROM cte)) + 
    (num2 in (SELECT val FROM cte)) + 
    (num3 in (SELECT val FROM cte)) + 
    (num4 in (SELECT val FROM cte)) + 
    (num5 in (SELECT val FROM cte)) matches
  FROM tablename 
) t
GROUP BY t.matches
ORDER BY t.matches DESC
请参阅。
结果:


如果您遵循第一个标准形式,并且不使用重复的列组,那么您的任务将更加容易

相反,创建第二个表,其中
num
列都是相同的列

CREATE TABLE numtable (
  groupid INT NOT NULL,
  num INT NOT NULL,
  PRIMARY KEY (groupid, num)
);
对于旧表中的每一行,您在该表中最多放置五行。如果要使用多个列来存储可比较的值,则需要在自己的表中有一个多值属性

然后,您可以这样查询以查找具有五个匹配项的groupid:

SELECT groupid
FROM numtable
WHERE num IN (@val1, @val2, @val3, @val4, @val5)
GROUP BY groupid
HAVING COUNT(*) = 5
然后替换最后一行以查找具有三个或四个匹配项的groupid,例如:

...
HAVING COUNT(*) = 4
如果您想知道每个匹配数有多少个groupid:

SELECT matches, COUNT(*) AS num_matches
FROM (
    SELECT groupid, COUNT(*) AS matches
    FROM numtable
    WHERE num IN (@val1, @val2, @val3, @val4, @val5)
    GROUP BY groupid
    HAVING COUNT(*) IN (3,4,5)
) AS t
GROUP BY matches

这种问题是糟糕的模式的症状design@Strawberry您建议如何更改模式?这似乎是一个干净而简单的解决方案,尽管我自己也不知道。明天我将尝试一下,并让您知道它是否使用真实数据工作。@Nekomajin42“干净和简单”的定义肯定不同@草莓,你对什么是答案肯定有不同的定义。不,我想我们在这个问题上基本一致。@草莓,不,我不这么认为。我明天也会试试这个。谢谢
SELECT matches, COUNT(*) AS num_matches
FROM (
    SELECT groupid, COUNT(*) AS matches
    FROM numtable
    WHERE num IN (@val1, @val2, @val3, @val4, @val5)
    GROUP BY groupid
    HAVING COUNT(*) IN (3,4,5)
) AS t
GROUP BY matches