在 SQL table 的多个列中查找重复值并计算字符数
Finding duplicate values in multiple colums in a SQL table and count for chars
参考这个问题:
我有以下 table 结构:
id name1 name2 name3 ...
1 Hans Peter Frank
2 Hans Frank Peter
3 Hans Peter Frank
4 Paul Peter Hans
.
.
.
我使用以下命令来显示重复项和计数:
SELECT COUNT(name1), name1, name2, name3
FROM table
GROUP BY name1, name2, name3
HAVING (COUNT(name1) > 1) AND (COUNT(name2) > 1) AND (COUNT(name3) > 1)
这个命令给了我 2 的计数。我想知道第二行如何也可以算作重复。
很遗憾,原问题的解决方案 () 不适用于 char
首先在 CTE 中使用 UNION ALL
规范化 table,以便将 3 个名称中的每一个都放在单独的行中。
然后使用 ROW_NUMBER()
window 函数,您可以按字母顺序排列 3 个名称,以便您可以按它们分组:
WITH cte(id, name) AS (
SELECT id, name1 FROM tablename
UNION ALL
SELECT id, name2 FROM tablename
UNION ALL
SELECT id, name3 FROM tablename
)
SELECT COUNT(*) count, name1, name2, name3
FROM (
SELECT id,
MAX(CASE WHEN rn = 1 THEN name END) name1,
MAX(CASE WHEN rn = 2 THEN name END) name2,
MAX(CASE WHEN rn = 3 THEN name END) name3
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY name) rn
FROM cte
)
GROUP BY id
)
GROUP BY name1, name2, name3
HAVING COUNT(*) > 1;
另一种方法,它使用与您之前关于数值的问题类似的逻辑,使用字符串函数 REPLACE()
而不是 window 函数,但仅当每行中有 3 个名称时才有效不同:
SELECT COUNT(*) count,
MIN(name1, name2, name3) name_1,
REPLACE(
REPLACE(
REPLACE(name1 || ',' || name2 || ',' || name3, MIN(name1, name2, name3), ''),
MAX(name1, name2, name3), ''), ',', ''
) name_2,
MAX(name1, name2, name3) name_3
FROM tablename
GROUP BY name_1, name_2, name_3
HAVING COUNT(*) > 1;
参见demo。
不是特别漂亮,而是一种不同的方法来旋转列,然后将它们聚合为一个字符串并计算重复项。不幸的是,在 SQL Lite 中,group_concat 函数无法指定组内的任何顺序,这会强制进行另一层嵌套和 row_number .我猜这是 SQL lite!
的一部分
如果您想显示所有重复的变体,您可以删除 Seq 和过滤条件。
with cte as (
select Duplicates, name1, name2, name3,
Row_Number() over(partition by Duplicates order by name1,name2,name3) Seq
from (
select count(*) over(partition by allnames) Duplicates, name1, name2, name3
from t
left join (
select Id, group_concat(Dname) allNames
from (
select Id, Dname, row_number() over (partition by Id order by Dname) seq
from (
select id, name1 Dname from t union all
select id, name2 from t union all
select id, name3 from t
)x
)x
group by Id
order by seq
)d on d.id=t.id
)d
)
select Duplicates, name1, name2, name3
from cte
where duplicates>1 and seq=1
您只需要按所有列对行进行排序,对它们进行分组,计算重复项,并找到重复项最多的记录。在 SQL 中编写它是相当麻烦的,它使用包含 window 函数的嵌套查询。 SQL 语句很长而且难以阅读。另一种方法是从数据库中导出数据并在 Python 或 SPL 中处理它。 SPL,open-source Java 包,更容易集成到 Java 程序中并生成更简单的代码。它仅用三行代码就完成了任务:
A
1
=sqlite.query("select name1,name2,name3 from names")
2
=A1.group([#1,#2,#3].sort();~.len()).maxp(#2)
3
=create(count,name1,name2,name3).record([A2.#2,A2.#1(1),A2.#1(2),A2.#1(3)])
参考这个问题:
我有以下 table 结构:
id name1 name2 name3 ...
1 Hans Peter Frank
2 Hans Frank Peter
3 Hans Peter Frank
4 Paul Peter Hans
.
.
.
我使用以下命令来显示重复项和计数:
SELECT COUNT(name1), name1, name2, name3
FROM table
GROUP BY name1, name2, name3
HAVING (COUNT(name1) > 1) AND (COUNT(name2) > 1) AND (COUNT(name3) > 1)
这个命令给了我 2 的计数。我想知道第二行如何也可以算作重复。
很遗憾,原问题的解决方案 (
首先在 CTE 中使用 UNION ALL
规范化 table,以便将 3 个名称中的每一个都放在单独的行中。
然后使用 ROW_NUMBER()
window 函数,您可以按字母顺序排列 3 个名称,以便您可以按它们分组:
WITH cte(id, name) AS (
SELECT id, name1 FROM tablename
UNION ALL
SELECT id, name2 FROM tablename
UNION ALL
SELECT id, name3 FROM tablename
)
SELECT COUNT(*) count, name1, name2, name3
FROM (
SELECT id,
MAX(CASE WHEN rn = 1 THEN name END) name1,
MAX(CASE WHEN rn = 2 THEN name END) name2,
MAX(CASE WHEN rn = 3 THEN name END) name3
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY name) rn
FROM cte
)
GROUP BY id
)
GROUP BY name1, name2, name3
HAVING COUNT(*) > 1;
另一种方法,它使用与您之前关于数值的问题类似的逻辑,使用字符串函数 REPLACE()
而不是 window 函数,但仅当每行中有 3 个名称时才有效不同:
SELECT COUNT(*) count,
MIN(name1, name2, name3) name_1,
REPLACE(
REPLACE(
REPLACE(name1 || ',' || name2 || ',' || name3, MIN(name1, name2, name3), ''),
MAX(name1, name2, name3), ''), ',', ''
) name_2,
MAX(name1, name2, name3) name_3
FROM tablename
GROUP BY name_1, name_2, name_3
HAVING COUNT(*) > 1;
参见demo。
不是特别漂亮,而是一种不同的方法来旋转列,然后将它们聚合为一个字符串并计算重复项。不幸的是,在 SQL Lite 中,group_concat 函数无法指定组内的任何顺序,这会强制进行另一层嵌套和 row_number .我猜这是 SQL lite!
的一部分如果您想显示所有重复的变体,您可以删除 Seq 和过滤条件。
with cte as (
select Duplicates, name1, name2, name3,
Row_Number() over(partition by Duplicates order by name1,name2,name3) Seq
from (
select count(*) over(partition by allnames) Duplicates, name1, name2, name3
from t
left join (
select Id, group_concat(Dname) allNames
from (
select Id, Dname, row_number() over (partition by Id order by Dname) seq
from (
select id, name1 Dname from t union all
select id, name2 from t union all
select id, name3 from t
)x
)x
group by Id
order by seq
)d on d.id=t.id
)d
)
select Duplicates, name1, name2, name3
from cte
where duplicates>1 and seq=1
您只需要按所有列对行进行排序,对它们进行分组,计算重复项,并找到重复项最多的记录。在 SQL 中编写它是相当麻烦的,它使用包含 window 函数的嵌套查询。 SQL 语句很长而且难以阅读。另一种方法是从数据库中导出数据并在 Python 或 SPL 中处理它。 SPL,open-source Java 包,更容易集成到 Java 程序中并生成更简单的代码。它仅用三行代码就完成了任务:
A | |
---|---|
1 | =sqlite.query("select name1,name2,name3 from names") |
2 | =A1.group([#1,#2,#3].sort();~.len()).maxp(#2) |
3 | =create(count,name1,name2,name3).record([A2.#2,A2.#1(1),A2.#1(2),A2.#1(3)]) |