SQL - 选择具有最匹配列的行

Posted

技术标签:

【中文标题】SQL - 选择具有最匹配列的行【英文标题】:SQL - select row with most matching columns 【发布时间】:2013-10-24 09:34:51 【问题描述】:

我是数据库和 SQL 的新手,3 天以来一直在尝试解决这个问题。我有一个使用 JDBC 查询 SQLite 数据库的 Java 应用程序。到目前为止,这工作得很好。但我无法弄清楚检索所需行所需的 SQL 查询。该表如下所示:

rowid | application | dstIP          | dstPort | value_to_return
      |             |                |         | 
0     | NULL        | NULL           | NULL    | 26
1     | NULL        | NULL           | 80      | 1
2     | NULL        | 192.168.178.31 | NULL    | 2
3     | NULL        | 192.168.178.31 | 80      | 3
4     | firefox     | NULL           | NULL    | 4
5     | firefox     | NULL           | 80      | 5
6     | firefox     | 192.168.178.31 | NULL    | 6 
7     | firefox     | 192.168.178.31 | 80      | 7

我的目标是获取大多数列匹配的行,如果没有列匹配,则应选择第 0 行。 这里有一些例子:

input                     -> row

firefox 192.168.178.31 80 -> 7
chrome  192.168.178.31 81 -> 2
chrome  192.168.178.30 82 -> 0
someapp 192.168.178.29 80 -> 1

到目前为止我最好的猜测是这个查询

SELECT * FROM table WHERE (application IS ? OR application IS NULL)
                      AND (dstIP IS  ? OR dstIP IS NULL)
                      AND (dstPort IS ? OR dstPort IS NULL)
                      ORDER BY application;

?s 被相应的输入值替换。此查询在不匹配的情况下返回第 0 行。但如果有多个匹配项,它当​​然会返回几行。 我可以在 Java 应用程序中选择我需要的行,但我希望数据库为我工作。 如果存储过程是解决此问题的更好选择,我可以更改数据库,因为 SQLite 不支持。 我希望我对问题的描述足够准确。任何帮助将不胜感激。

【问题讨论】:

【参考方案1】:

这应该可以解决问题:

SELECT * FROM (
    SELECT *, CASE application WHEN ? THEN 1 WHEN NULL THEN 0 ELSE NULL END
            + CASE dstIP WHEN ? THEN 1 WHEN NULL THEN 0 ELSE NULL END
            + CASE dstPort WHEN ? THEN 1 WHEN NULL THEN 0 ELSE NULL END AS Matches
    FROM table WHERE Matches IS NOT NULL
) GROUP BY application, dstIP, dstPort ORDER BY Matches DESC;

Matches 列将计算所有列匹配或不匹配时为NULL

GROUP BY 没有聚合函数将捕获第一行(我希望!),这是最大匹配,因为内部查询是降序排序的。

编辑:新版本:

SELECT *, CASE WHEN application IS ? THEN 1 WHEN application IS NULL THEN 0 ELSE NULL END
        + CASE WHEN dstIP IS ? THEN 1 WHEN dstIP IS NULL THEN 0 ELSE NULL END
        + CASE WHEN dstPort IS ? THEN 1 WHEN dstPort IS NULL THEN 0 ELSE NULL END AS Matches
FROM t
WHERE Matches IS NOT NULL
ORDER BY Matches DESC
LIMIT 1;

优点:也可以比较NULL。缺点:找到相同排名的匹配时,仅显示 1 个匹配。

【讨论】:

它看起来不错,但我无法测试它。它在 WHERE 附近显示语法错误。我对 SQL 太缺乏经验了 :( 我目前正在测试内部 SELECT。似乎当一列没有匹配时,这不起作用,因为 ELSE NULL 分支。那么 Matches 列应该是 2 但它是 NULL。但我知道这是如何工作的基本概念。给我一点时间=) 当匹配排名相同时,我将选择返回的最大值,所以这应该没问题。给我一点时间来测试一下 =) 很好,我最终得到了几乎相同的结果,我在您的答案中对其进行了编辑。非常感谢您的帮助!让我感到困惑的是,您可以在 SQL 中添加“虚拟行”进行操作。学到了一些新东西 =)

以上是关于SQL - 选择具有最匹配列的行的主要内容,如果未能解决你的问题,请参考以下文章

MySQL选择其他表中没有匹配列的行

SQL - 如何选择具有最大值列的行

SQL - 选择所有不匹配空行的行

选择同一表 SQL 中两列之间存在一对一匹配的行

SQL Server:选择列中多次出现正则表达式匹配的行

如何从Oracle中的另一个子查询中选择具有最大列的行