首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SQL:如何合并不区分大小写的重复项

SQL:如何合并不区分大小写的重复项
EN

Stack Overflow用户
提问于 2013-08-17 04:20:44
回答 3查看 5.9K关注 0票数 10

在将重复的记录合并到一个文件中时,最好的方法是什么?

我遇到了这样的情况:表中记录着球员的名字和记录:

代码语言:javascript
复制
stats
-------------------------------
nick     totalgames     wins   ...
John     100            40
john     200            97
Whistle  50             47
wHiStLe  75             72
...

我需要合并尼克被复制的行(忽略大小写时),并将记录合并为一个,如下所示:

代码语言:javascript
复制
    stats
    -------------------------------
    nick     totalgames     wins   ...
    john     300            137
    whistle  125            119
    ...

我在Postgres做这件事。做这件事最好的方法是什么?

我知道,通过这样做,可以获得存在重复项的名称:

代码语言:javascript
复制
select lower(nick) as nick, totalgames, count(*) 
from stats 
group by lower(nick), totalgames
having count(*) > 1;

我想到了这样的事情:

代码语言:javascript
复制
update stats
set totalgames = totalgames + s.totalgames
from (that query up there) s
where lower(nick) = s.nick

但这不能正常工作。我似乎仍然无法删除包含重复名称的其他重复行。我能做什么?有什么建议吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-08-17 05:30:51

SQL Fiddle

这是您的最新消息:

代码语言:javascript
复制
 UPDATE stats
 SET totalgames = x.games, wins = x.wins
 FROM (SELECT LOWER(nick) AS nick, SUM(totalgames) AS games, SUM(wins) AS wins
     FROM stats
      GROUP BY LOWER(nick) ) AS x
 WHERE LOWER(stats.nick) = x.nick;

下面是要清除重复行的删除:

代码语言:javascript
复制
 DELETE FROM stats USING stats s2
 WHERE lower(stats.nick) = lower(s2.nick) AND stats.nick < s2.nick;

(请注意,“update...from”和“delete...using”语法是特定于Postgres的,并且是从这个答案这个答案中无耻地窃取的。)

您可能还需要运行这个程序来删除所有的名称:

代码语言:javascript
复制
 UPDATE STATS SET nick = lower(nick);

在小写版本的“nick”上添加一个唯一索引(或向该列添加一个约束,以不允许非小写值):

代码语言:javascript
复制
CREATE UNIQUE INDEX ON stats (LOWER(nick)); 
票数 10
EN

Stack Overflow用户

发布于 2013-08-17 15:25:54

这一切都可以在一个语句中完成,使用RETURNING

代码语言:javascript
复制
-- The data
CREATE TABLE stats
        ( nick VARCHAR PRIMARY KEY
        , totalgames INTEGER NOT NULL DEFAULT 0
        , wins INTEGER NOT NULL DEFAULT 0
        );

INSERT INTO stats(nick, totalgames,wins) VALUES
 ( 'John', 100, 40) ,( 'john', 200, 97)
,( 'Whistle', 50, 47) ,( 'wHiStLe', 75, 72)
, ( 'Single', 42, 13 ) -- this person has only one record
        ;
SELECT * FROM stats;

-- The query:
WITH upd AS (
        UPDATE stats dst
        SET totalgames = src.totalgames
                , wins = src.wins
        FROM ( SELECT MIN(nick) AS nick -- pick the "lowest" nick as the canonical nick
                , SUM(totalgames) AS totalgames
                , SUM(wins) AS wins
                FROM stats
                GROUP BY lower(nick)
                ) src
        WHERE dst.nick = src.nick
        RETURNING dst.nick -- only the records that have been updated
        )
-- Delete the records that were NOT updated.
DELETE FROM stats del
WHERE NOT EXISTS (
        SELECT * FROM upd
        WHERE upd.nick = del.nick
        )
        ;

SELECT * FROM stats;

输出:

代码语言:javascript
复制
INSERT 0 5
  nick   | totalgames | wins 
---------+------------+------
 John    |        100 |   40
 john    |        200 |   97
 Whistle |         50 |   47
 wHiStLe |         75 |   72
 Single  |         42 |   13
(5 rows)

DELETE 2
  nick   | totalgames | wins 
---------+------------+------
 wHiStLe |        125 |  119
 john    |        300 |  137
 Single  |         42 |   13
(3 rows)
票数 3
EN

Stack Overflow用户

发布于 2013-08-17 05:34:58

UPDATE stats SET totalgames=s.totalgames, wins=s.wins

FROM (SELECT lower(nick) AS nick,SUM(totalgames) AS totalgames,SUM(wins) AS wins FROM stats GROUP BY lower(nick))s WHERE lower(nick)=s.nick;

DELETE FROM stats WHERE

lower(nick) IN (SELECT lower(nick) FROM stats GROUP BY lower(nick) HAVING COUNT(*)>1)

AND NOT lower(nick) IN (SELECT first(nick) FROM stats GROUP BY lower(nick)应该能工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18285067

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档