计算 SQL 表中关于列的相同记录

Posted

技术标签:

【中文标题】计算 SQL 表中关于列的相同记录【英文标题】:Counting identical records in a SQL table with respect to a column 【发布时间】:2021-02-21 07:29:10 【问题描述】:

问题描述

我正在寻找一个可以使用表 1 创建表 2 的 SQL 查询。我已经想到了这样做的方法,但它不是很有说服力,如果可能的话,我更喜欢更简单的方法。

表 1:

ID Col_1 Col_2 Col_3 Col_4
01 A Q R U
02 A Q R P
03 A Q R U
04 A Q R P
05 A Q T U
06 A Q T P
07 A Q T U
08 A Q T P
09 A Q R U
10 B Q R P
11 B Q R U
12 B Q R P
13 B Q T U
14 C Q T P
15 C Q T U
16 C Q T U
17 C Q R P
18 C Q R U
19 C Q R P
20 C Q R U

表 2:

ID Col_1 Col_2 Col_3 Col_4
01 9 9 5 3
02 9 9 5 2
03 9 9 5 3
04 9 9 5 2
05 9 9 4 2
06 9 9 4 2
07 9 9 4 2
08 9 9 4 2
09 9 9 5 3
10 4 4 3 2
11 4 4 3 1
12 4 4 3 2
13 4 4 1 1
14 7 7 3 1
15 7 7 3 2
16 7 7 3 2
17 7 7 4 2
18 7 7 4 2
19 7 7 4 2
20 7 7 4 2

表2中的数字生成如下:

在表 2 的 Col_1 中,数字是所有具有相同 Col_1 值的 ID 的计数。 在表 2 的 Col_2 中,数字是具有相同 Col_1 AND Col_2 值的所有 ID 的计数。 在表 2 的 Col_3 中,数字是具有相同 Col_1 的所有 ID 的计数 AND Col_2 AND Col_3价值。 在表 2 的 Col_4 中,数字是具有相同 Col_1 的所有 ID 的计数 AND Col_2 AND Col_3 AND Col_4 值。

示例: 在表 1 中,ID01 的 Col_1 值为“A”。 “A”与 02、03、04、05、06、07、08 和 09(其他 8 个 ID)匹配,因此数字为 9。 ID01 的 Col_2 值为“Q”。 Col_1 中的“A”AND Col_2 中的“Q”与 02、03、04、05、06、07、08 和 09(8 个其他 ID)匹配,因此数字是 9。 ID01 的 Col_3 值为“R”。 Col_1 中的“A”AND Col_2 中的“Q”AND Col_3 中的“R”与 02、03 匹配、04 和 09(4 个其他 ID),所以数字是 5。 ID01 的 Col_4 值为“U”。 Col_1 中的“A”AND Col_2 中的“Q”AND Col_3 中的“R”AND Col_4 中的“U”与 03 和 09(另外 2 个 ID)匹配,因此数字为 3。

基本上,我们试图在表 1 中找到相同 ID 的总数 - 相对于感兴趣的 Col。

我尝试过的

我想出了一种方法来获取表 2 中的数字,使用简短的 SQL 查询:

-- Somehow use in Table 2 
SELECT 
    col_1,
    col_2,
    col_3,
    col_4,
    COUNT() AS ct
FROM sample_table
GROUP BY 
    col_1,
    col_2,
    col_3,
    col_4
ORDER BY ct DESC;

返回

Col_1 Col_2 Col_3 Col_4 ct
A Q R U 3
A Q R P 2
A Q T P 2
A Q T U 2
B Q R P 2
C Q R P 2
C Q R U 2
C Q T U 2
B Q R U 1
B Q T U 1
C Q T P 1

这是表 2 的 Col_4 的正确数字 (ct)。我只需要匹配此输出中的列和表 1。我还可以GROUP BYfewer 列来获得 Col_3、Col_2 的正确数字,和 1. 例如

SELECT 
    col_1,
    col_2,
    col_3,
    COUNT() AS ct
FROM samptbl
GROUP BY 
    col_1,
    col_2,
    col_3
ORDER BY ct DESC;
Col_1 Col_2 Col_3 ct
A Q R 5
A Q T 4
C Q R 4
B Q R 3
C Q T 3
B Q T 1

我现在在 SQLite 中执行此操作,但如果需要,我可以使用任何其他语言(PostgreSQL、Python)。如果可能的话,我真的希望这在 SQL 中是 100%。我正在使用的数据集很大,因此需要良好的效率。

【问题讨论】:

【参考方案1】:

你可以用窗口函数COUNT()

SELECT ID,
       COUNT(*) OVER (PARTITION BY Col_1) Col_1,
       COUNT(*) OVER (PARTITION BY Col_1, Col_2) Col_2,
       COUNT(*) OVER (PARTITION BY Col_1, Col_2, Col_3) Col_3,
       COUNT(*) OVER (PARTITION BY Col_1, Col_2, Col_3, Col_4) Col_4
FROM table1
ORDER BY ID

无需任何更改,它也适用于 Postgresql。 请参阅demo。

【讨论】:

谢谢你,我试过这个,我运行了大约 150 秒。比我想象的要好!您对这种方法与 Turo 的效率有何见解。 (我会同时尝试并报告...) 如果 150 秒比您希望的要好,那么您必须有一个相当大的表。通常窗口函数比简单的聚合执行得更好。在您的情况下,您可以使用每种情况的索引来测试性能:Col_1、(Col_1、Col_2)、(Col_1、Col_2、Col_3)和(Col_1、Col_2、Col_3、Col_4)。【参考方案2】:

您可以使用 CREATE TABLE AS 和简单的子选择:

CREATE TABLE TABLE2 AS
SELECT a.ID, 
        (SELECT COUNT(ID) FROM samptbl WHERE a.col_1 = col_1) as col_1, 
        (SELECT COUNT(ID) FROM samptbl WHERE a.col_1 = col_1 and a.col_2 = col_2)  as col_2, 
        (SELECT COUNT(ID) FROM samptbl WHERE a.col_1 = col_1 and a.col_2 = col_2 and a.col_3 = col_3)  as col_3,
        (SELECT COUNT(ID) FROM samptbl WHERE a.col_1 = col_1 and a.col_2 = col_2 and a.col_3 = col_3 and a.col_4 = col_4)  as col_4
FROM samptbl a;

db-fiddle

但是效率不会很好……

【讨论】:

非常感谢,这非常有用!这就是我脑海中的方向。我没有将它的性能与 forpas 的解决方案进行比较。

以上是关于计算 SQL 表中关于列的相同记录的主要内容,如果未能解决你的问题,请参考以下文章

sql语句查询一个表中某一列的相同数据

SQL Join与子查询计算不同表中具有相同ID的记录数

在保留列的同时计算具有相同值的行

如何使用sql从具有不同列的两个表中获取不同的记录

在两个不同的表中创建具有相同列的视图 SQL

SQL中关于返回查询记录条数的语句