簡體   English   中英

選擇列中最后n個字符不唯一的所有記錄

[英]Select all records where last n characters in column are not unique

我對mysql有一些奇怪的要求。 我應該從表中選擇所有記錄,其中最后6個字符不是唯一的。

例如,如果我有表:

在此處輸入圖片說明

我應該選擇第1行和第3行,因為此值的最后6個字母不是唯一的。

你有什么想法要實現嗎? 謝謝你的幫助。

這樣的事情應該起作用:

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)

但這並不快。 這需要全表掃描。 也許您應該重新考慮您的問題。

編輯:我以前對這個問題有一個錯誤的理解,我真的不想改變我最初的答案。 但是,如果我先前的回答在某些環境中不可接受,並且可能會誤導人們,則無論如何我都必須糾正它。

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進行了測試。 ;)

我對子查詢使用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

這就是您需要的:一個子查詢以獲取重復的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
        ) 

在這里擺弄

可能是快速的代碼,因為不涉及計數。

實時測試: 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的答案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的答案 我只是不知道他為什么使第二個答案不必要地復雜。

因此,這只是一個問題,或者選擇哪種代碼更易讀,請select from in select from join vs select from join 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秒

在此處輸入圖片說明

稍微整潔的代碼(如果使用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            |

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM