选择列中最后n个字符不唯一的所有记录

时间:2019-04-17 07:16:28

标签: mysql sql

我对mysql有一些奇怪的要求。 我应该从表中选择最后6个字符都不唯一的所有记录。

例如,如果我有桌子:

enter image description here

我应该选择第1行和第3行,因为此值的后6个字母不是唯一的。

您是否知道如何执行此操作? 谢谢您的帮助。

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

的情况下避免mysql错误的解决方案
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
        ) 

Fiddle here

答案 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的answercorrelated 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)                                                

enter image description here

我的答案(相关的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)          
)

enter image description here

直接查询是最快的,无连接的查询,只是普通的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
    ) 

结果:

enter image description here


使用的测试数据:

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秒

enter image description here

IN方法:

无索引:3.719秒

具有索引:2.722秒

enter image description here

答案 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            |