我对mysql有一些奇怪的要求。 我应该从表中选择最后6个字符都不唯一的所有记录。
例如,如果我有桌子:
我应该选择第1行和第3行,因为此值的后6个字母不是唯一的。
您是否知道如何执行此操作? 谢谢您的帮助。
答案 0 :(得分:1)
类似的方法应该起作用:
SELECT `mytable`.*
FROM (SELECT RIGHT(`value`, 6) AS `ending` FROM `mytable` GROUP BY `ending` HAVING COUNT(*) > 1) `grouped`
INNER JOIN `mytable` ON `grouped`.`ending` = RIGHT(`value`, 6)
但是速度不快。这需要全表扫描。也许您应该重新考虑您的问题。
答案 1 :(得分:1)
已编辑:我之前对该问题的理解有误,因此我真的不想更改初始答案中的任何内容。但是,如果我先前的回答在某些环境下不可接受,并且可能会误导人们,那么我必须以任何方式纠正它。
SELECT GROUP_CONCAT(id),RIGHT(VALUE,6)
FROM table1
GROUP BY RIGHT(VALUE,6) HAVING COUNT(RIGHT(VALUE,6)) > 1;
由于该问题已经有了很好的答案,因此我以略有不同的方式进行了查询。而且我已经用sql_mode=ONLY_FULL_GROUP_BY
进行了测试。 ;)
答案 2 :(得分:1)
我对子查询使用JOIN,在该子查询中,我计算n
(在我的示例中为2)最后一个字符的每个唯一组合的出现次数
SELECT t.*
FROM t
JOIN (SELECT RIGHT(value, 2) r, COUNT(RIGHT(value, 2)) rc
FROM t
GROUP BY r) c ON c.r = RIGHT(value, 2) AND c.rc > 1
答案 3 :(得分:1)
这就是您需要的:一个子查询以获取重复的right(value,6),而主查询则根据该条件获取行。
SELECT t.* FROM t WHERE RIGHT(`value`,6) IN (
SELECT RIGHT(`value`,6)
FROM t
GROUP BY RIGHT(`value`,6) HAVING COUNT(*) > 1);
更新
这是在出现sql_mode=only_full_group_by
SELECT t.* FROM t WHERE RIGHT(`value`,6) IN (
SELECT DISTINCT right_value FROM (
SELECT RIGHT(`value`,6) AS right_value,
COUNT(*) AS TOT
FROM t
GROUP BY RIGHT(`value`,6) HAVING COUNT(*) > 1) t2
)
答案 4 :(得分:1)
由于不涉及计数,因此可能是快速代码。
实时测试:https://www.db-fiddle.com/f/dBdH9tZd4W6Eac1TCRXZ8U/0
select *
from tbl outr
where not exists
(
select 1 / 0 -- just a proof that this is not evaluated. won't cause division by zero
from tbl inr
where
inr.id <> outr.id
and right(inr.value, 6) = right(outr.value, 6)
)
输出:
| id | value |
| --- | --------------- |
| 2 | aaaaaaaaaaaaaa |
| 4 | aaaaaaaaaaaaaaB |
| 5 | Hello |
逻辑是测试不等于外部行的相同ID的其他行。如果这些其他行与外部行的右6个字符相同,则不要显示该外部行。
更新
我误解了OP的意图。是相反的。无论如何,只要颠倒逻辑即可。使用EXISTS代替NOT EXISTS
实时测试:https://www.db-fiddle.com/f/dBdH9tZd4W6Eac1TCRXZ8U/3
select *
from tbl outr
where exists
(
select 1 / 0 -- just a proof that this is not evaluated. won't cause division by zero
from tbl inr
where
inr.id <> outr.id
and right(inr.value, 6) = right(outr.value, 6)
)
输出:
| id | value |
| --- | ----------- |
| 1 | abcdePuzzle |
| 3 | abcPuzzle |
更新
测试了查询。我的答案(相关的EXISTS
方法)的性能不是最佳的。只要保持我的回答,其他人就会知道应该避免什么方法:)
GhostGambler的answer比correlated EXISTS
方法快。对于500万行,他的答案仅需2.762秒:
explain analyze
SELECT
tbl.*
FROM
(
SELECT
RIGHT(value, 6) AS ending
FROM
tbl
GROUP BY
ending
HAVING
COUNT(*) > 1
) grouped
JOIN tbl ON grouped.ending = RIGHT(value, 6)
我的答案(相关的EXISTS
)耗时4.08秒:
explain analyze
select *
from tbl outr
where exists
(
select 1 / 0 -- just a proof that this is not evaluated. won't cause division by zero
from tbl inr
where
inr.id <> outr.id
and right(inr.value, 6) = right(outr.value, 6)
)
直接查询是最快的,无连接的查询,只是普通的IN查询。 2.722秒。它具有与JOIN方法几乎相同的性能,因为它们具有相同的执行计划。这是kiks73的answer。我只是不知道他为什么使第二个答案不必要地复杂。
所以这只是一个口味问题,还是选择哪种代码更易读select from in
对比select from join
explain analyze
SELECT *
FROM tbl
where right(value, 6) in
(
SELECT
RIGHT(value, 6) AS ending
FROM
tbl
GROUP BY
ending
HAVING
COUNT(*) > 1
)
结果:
使用的测试数据:
CREATE TABLE tbl (
id INTEGER primary key,
value VARCHAR(20)
);
INSERT INTO tbl
(id, value)
VALUES
('1', 'abcdePuzzle'),
('2', 'aaaaaaaaaaaaaa'),
('3', 'abcPuzzle'),
('4', 'aaaaaaaaaaaaaaB'),
('5', 'Hello');
insert into tbl(id, value)
select x.y, 'Puzzle'
from generate_series(6, 5000000) as x(y);
create index ix_tbl__right on tbl(right(value, 6));
不带索引并且在tbl(right(value, 6))
上具有索引的性能:
JOIN
方法:
无索引:3.805秒
具有索引:2.762秒
IN
方法:
无索引:3.719秒
具有索引:2.722秒
答案 5 :(得分:0)
只需稍微整洁的代码(如果使用MySQL 8.0)。虽然不能保证性能
实时测试:https://www.db-fiddle.com/f/dBdH9tZd4W6Eac1TCRXZ8U/1
select x.*
from
(
select
*,
count(*) over(partition by right(value, 6)) as unique_count
from tbl
) as x
where x.unique_count = 1
输出:
| id | value | unique_count |
| --- | --------------- | ------------ |
| 2 | aaaaaaaaaaaaaa | 1 |
| 4 | aaaaaaaaaaaaaaB | 1 |
| 5 | Hello | 1 |
更新
我误解了OP的意图。是相反的。只需更改计数:
select x.*
from
(
select
*,
count(*) over(partition by right(value, 6)) as unique_count
from tbl
) as x
where x.unique_count > 1
输出:
| id | value | unique_count |
| --- | ----------- | ------------ |
| 1 | abcdePuzzle | 2 |
| 3 | abcPuzzle | 2 |