如何在SQL中查找以相同字符串结尾的行?

时间:2017-09-19 18:27:47

标签: mysql mysql-5.7 mysql-5.6

我有一个类似于此处的问题:How to find rows in SQL that start with the same string (similar rows)?,此解决方案适用于MySQL 5.6但不适用于5.7。

我有一个包含多列的数据库(t),重要的是id和filepath,我想要完成的是检索所有具有相同最后5个字符的文件路径。以下适用于MySQL5.6,第二个SELECT在5.7中工作正常:

SELECT id, filepath FROM t
WHERE SUBSTRING(filepath, -5) IN
(
  SELECT SUBSTRING(filepath, -5) 
  FROM t 
  GROUP BY SUBSTRING(filepath, -5)
  HAVING COUNT(*) > 1
)

但是当我尝试在5.7上运行它时,我得到了错误

Expression #1 of HAVING clause is not in GROUP BY clause and contains 
nonaggregated column 't.filepath' which is not functionally dependent on 
columns in GROUP BY clause; this is incompatible with 
sql_mode=only_full_group_by

示例数据:

id     filepath
1      /Desktop/file1.txt
2      /Desktop/file2.txt
3      /Desktop/file1.txt

我希望返回id为1和3的行。如何为MySQL5.7修复此问题?

编辑:也有人能指出我正确的方向让SQL删除重复项吗?所以我想删除id 3的条目,但保留id 1和2的条目。

3 个答案:

答案 0 :(得分:1)

请阅读有关GROUP BY和sql_mode only_full_group_by的mysql文档(如您的错误消息所示): https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

我认为将内部查询更改为可能会解决问题:

SELECT SUBSTRING(filepath, -5) AS fpath
FROM t 
GROUP BY fpath
HAVING COUNT(fpath) > 1

修改:

关于为什么添加“AS fpath”有效的问题: 添加别名“fpath”只是一种干净的方法。 ONLY_FULL_GROUP_BY的要点是您在SELECT,HAVING或ORDER BY中使用的每个字段也必须位于GROUP BY中。

所以我添加了fpath-alias有多种原因:

  • 对于性能:您编写的查询有两次SUBSTRING(文件路径,-5), 对性能不利。 Mysql必须执行两次SUBSTRING调用, 而在我的情况下,它只需要做一次(每行)。
  • 要修复分组问题:您在拥有COUNT(),但“”不在您的GROUP BY语句中(我甚至都没有确定这是否可行)。你必须计算“某事”,所以既然“fpath”在你的SELECT和你的GROUP BY中,使用它作为你的COUNT()就可以解决问题。

答案 1 :(得分:1)

我不希望将子查询放在IN()谓词中,因为MySQL倾向于多次运行子查询。

您可以使用不同的方式编写查询,以将子查询作为派生表放在FROM子句中。这将使MySQL只运行子查询一次。

SELECT id, filepath 
FROM (
  SELECT SUBSTRING(filepath, -5) AS suffix, COUNT(*) AS count
  FROM t 
  GROUP BY suffix
  HAVING count > 1
) AS t1
JOIN t AS t2 ON SUBSTRING(t2.filepath, -5) = t1.suffix

这必然会进行表扫描,所以它会成为一个代价高昂的查询。在进行子串比较时,它不能使用索引。

要优化此功能,您可以创建一个带索引的虚拟列。

ALTER TABLE t 
  ADD COLUMN filepath_last VARCHAR(10) AS (SUBSTRING_INDEX(filepath, '/', -1)),
  ADD KEY (filepath_last);

然后您可以像这样查询它,并且至少子查询使用索引:

SELECT id, filepath 
FROM (
  SELECT filepath_last, COUNT(*) AS count
  FROM t 
  GROUP BY filepath_last
  HAVING count > 1
) AS t1
STRAIGHT_JOIN t AS t2 ON t2.filepath_last = t1.filepath_last

答案 2 :(得分:0)

最终为我工作的解决方案在这里找到:Disable ONLY_FULL_GROUP_BY

我运行SET @@sql_mode =然后only_full_group_by后跟一个字符串,其中包含第一个查询返回的除- name: ASSIGN VLAN TO TRUNK PORTS nxos_switchport: interface: "{{ item.interface }}" mode: trunk trunk_vlans: "{{ item.vlan | default('2600') }}" provider: "{{ provider }}" with_items: - interface: po850 - interface: po860 - interface: po865 - interface: po868 - interface: po871 - interface: po872 - interface: po875 - interface: po884 以外的所有值,但我还是对这是怎么回事无需更改SQL设置即可完成。