【问题标题】:Get rows that include value of input in specific cell, filter by other cell, return other cell values获取包含特定单元格中输入值的行,按其他单元格过滤,返回其他单元格值
【发布时间】:2017-02-28 22:09:51
【问题描述】:

感谢Paul Spiegel's answer 上一个问题,我在数据库dab 中有一个表tab,它由四列组成。一个简单的,一个 ID 列 (id),它也是主键 (int),一个 pat 列 (varchar(255)),一个 path 列 (varchar(191)),最后是 has_tree (位(1))。

id  pat     path    has_tree
1   AA      1       1
2   ABA     1/2     1
3   ABCA    1/3     1
4   ABA     1/5     0
5   AB      2       0
6   BBB     2/1     1
7   CAB     2/2     1
8   ABC     1/4     0
9   ABC     1/5/7   1
10  ABA     3/2     1

给定一个pat 值(如果存在),我想要

  • 所有唯一的pat 值(包括输入的has_tree==1),
  • 他们的路径包含输入的路径,
  • 在哪里has_tree == 1

所以输入 AA 应该返回 ['AA', 'ABA', 'ABCA', 'ABC']

重要的说明是输入patpath 不一定是单个项目“根路径”,换句话说:输入path 很可能类似于1/12/45/966,其中案例我想要所有唯一的pat 值,其中path1/12/45/966 的后代,has_tree1。另一个说明是路径可以很深,所以即使输入path1,结果也可以更深很多层,例如1/22/36/88/98/455/878/1205/2555.

Paul 建议了以下查询,该查询适用于建议的数据结构,但是您可以看到当前的结构和要求略有不同。 (另请注意,我有一个包含多个表的数据库。所以在数据库dab 中给定一个表tab 我想执行脚本。)

SELECT t.*
FROM tree t
CROSS JOIN tree r -- root
WHERE r.CELL = '3B0'
  AND t.path LIKE CONCAT(r.path, '%');

我正在尝试使用 PHP 执行此操作,然后调用一些 SQL 数据库。 是否可以以通用、高性能的形式编写它以使其适用于 PostgreSQL、MySQL 和其他?如果没有,我至少希望看到 MySQL 和 PostgreSQL 变体。

在上面 Paul 的示例代码的基础上,我认为应该是这样的,但我不确定。 我也不确定为什么JOIN 运算符是必要的,以及它在这种情况下的作用(我知道它通常做什么,但不知道为什么在这种情况下它是必要的)。我确信这段代码可以改进、修复,并使其更适用于所有 SQL 风格?此外,我没有看到我在下面的尝试在输出中包含当前输入 pat

SELECT t.pat
FROM `tab` t
JOIN `tab` r
WHERE r.pat = 'AA' -- input
  AND t.path LIKE CONCAT(r.path, '/', '%')
  AND t.has_tree = 1;

额外问题:我已索引除has_tree 之外的所有列。也为该列编制索引是否有益?

【问题讨论】:

    标签: mysql postgresql


    【解决方案1】:

    第一个注意事项:路径应以反斜杠结尾('1/''1/2/' 而不是'1''1/2')。这很重要,因为否则您无法匹配子树的根。示例:

    WHERE path LIKE '1/%'
    

    不会匹配'1',但会匹配'1/'

    您也可以不只是跳过查询中的反斜杠:

    WHERE path LIKE '1%'
    

    将匹配根'1',但也匹配'10..'

    现在你的问题:如果你已经知道根节点的路径,你不需要加入:

    SELECT * FROM tab WHERE path LIKE '1/%' AND has_tree
    

    要仅获得“独特”的拍子,您可以使用 DISTINCT 关键字:

    SELECT DISTINCT pat
    FROM tab
    WHERE path LIKE '1/%'
      AND has_tree
    

    就是这样。

    如果您不知道根路径而只知道 pat 值,则需要运行两个查询(首先获取路径然后获取后代)或使用连接。

    PostgreSQL:

    SELECT DISTINCT t.pat
    FROM tab t
    JOIN tab r ON t.path LIKE r.path || '%'
    WHERE r.pat = 'AA' -- input
      AND t.has_tree
    

    演示:http://rextester.com/EXZT43019

    MySQL:

    SELECT DISTINCT t.pat
    FROM tab t
    JOIN tab r ON t.path LIKE CONCAT(r.path, '%')
    WHERE r.pat = 'AA' -- input
      AND t.has_tree
    

    演示:http://rextester.com/DNHRJ83456

    注意:正如您将在 domo 中看到的,如果您更改模式,您还可以在 MySQL 中使用管道 (||) 进行连接:

    SET sql_mode=PIPES_AS_CONCAT;
    

    关于索引:布尔列上的索引通常不是很有用。但是,您只能确定是否对其进行了测试。对于给定的查询,(has_tree, path) 上的复合索引可能会提高性能。

    【讨论】:

    • 谢谢,这很好用——而且速度很快!我总是对 SQL 的表现感到惊讶。与主题问题稍有不同的是,路径上的唯一索引与“常规”索引之间的差异在数百万行中是否会很明显?
    • @BramVanroy 对于 SELECT 语句应该没有任何区别。使用唯一索引的插入和更新可能会慢一些。但是再一次 - 你只会确定你是否测试它(或者你分析实现)。但是 - 我可能总是这样定义逻辑上唯一的列。看看有多少诸如“我如何删除重复项?”之类的问题。在 SO 上被问到,因为人们错过了定义正确的唯一键。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多