我有一个类似于此处的问题: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的条目。答案 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有多种原因:
答案 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设置即可完成。