SQL 选择由 Ids 标识并由另一个表中的特定类型过滤的行列表中的所有第一项

Posted

技术标签:

【中文标题】SQL 选择由 Ids 标识并由另一个表中的特定类型过滤的行列表中的所有第一项【英文标题】:SQL Select all first items in a list of rows identified by Ids and filtered by a specific Type in another table 【发布时间】:2021-12-30 18:40:21 【问题描述】:

我需要创建一个以 ID 为键的表,其中新表中的一列的值是输入到另一个表的列中的最早值,其中行共享相同的 ID 并具有特定的类型标签。

例如,假设我想为每种水果输入名称和第一个值,输入类型为 A:

这些是我的桌子:

表 1

Key ID Name
1 1 Cherry
2 2 Grape

表2

Key ID Value EntryNum EntryType
1 1 21 1 A
2 1 32 2 B
3 1 4 3 B
4 1 15 4 A
5 2 3 1 B
6 2 8 2 A
7 2 16 3 B

这就是我想要的结果:

表3

ID Name EarliestEntry
1 Cherry 21
2 Grape 8

我尝试了以下查询,但它只是为所有 EarliestEntry 返回相同的值:

SELECT TABLE1.ID, TABLE2.Name,
   (SELECT Value FROM (SELECT ROW_NUMBER() OVER (ORDER BY TABLE2.EntryNum)
   as row_num, Value FROM TABLE2
   WHERE TABLE2.ID = TABLE1.ID AND TABLE2.EntryType = 'A')
   AS sub
   WHERE row_num = 1) AS EarliestEntry
INTO TABLE3
FROM TABLE2
INNER JOIN TABLE1 ON TABLE1.ID = TABLE2.ID
GROUP BY TABLE1.ID, TABLE2.Type, TABLE2.EntryNum

非常感谢您对此的帮助。谢谢

【问题讨论】:

【参考方案1】:

如果您想使用 ROW_NUMBER 函数,那么您需要将它放在 TABLE1 上并添加一个分区,如下所示:

WITH rn AS(
 SELECT a.Key, ROW_NUMBER() OVER(PARTITION BY a.ID ORDER BY a.EntryNum) AS rn
 FROM TABLE2 AS a
)
SELECT b.Name, a.Value AS EarliestValue
FROM TABLE2 AS a
INNER JOIN TABLE1 AS b ON b.ID = a.ID
INNER JOIN rn AS rn ON rn.key = a.key
WHERE rn.rn = 1

在您的示例中,您跳过了 PARTITION BY 子句,因此您只需获得 TABLE2 中所有值的数字。而不是每个 ID 的数字按升序排列的值。

【讨论】:

【参考方案2】:

根据您对三个表 TABLE1、TABLE2 和 TABLE3 的描述。

我稍微修改了你的脚本。感谢 Dale K 的评论,我用一些话解释了解决方案:第一次选择中显示的字段 TABLE2.Name 是错误的,因为 [name] 属于 TABLE1,所以正确的语法是 TABLE1.name。并且在 GROUP BY 子句中,字段 TABLE2.Type 可能会替换为 TABLE1.name 以符合聚合标准。所以脚本变成了:

 SELECT DISTINCT table1.id, table1.name,
  (SELECT Value FROM (SELECT ROW_NUMBER() OVER (ORDER BY table2.EntryNum)
   as row_num, Value FROM table2
   WHERE table2.id = table1.id AND table2.EntryType = 'A')
   AS sub
   WHERE row_num = 1) AS EarliestEntry
   INTO table3
FROM table2
INNER JOIN table1 ON table1.id = table2.id
GROUP BY table1.id, table1.name, table2.entrynum;

Here, you can verify the output 与 fiddle

【讨论】:

一个好的答案除了提供工作代码外,还可以用文字解释解决方案是什么。 请将您的解释放在您的回答中,而不是放在最终会被删除的评论中。【参考方案3】:

你把事情复杂化了。

只需对Table2 进行分区并获取行号,然后将其加入Table1 并仅过滤行号1

SELECT
  t1.Id,
  t1.Name,
  EarliestEntry = t2.Value
FROM Table1 t1
JOIN (
    SELECT *,
      rn = ROW_NUMBER() OVER (PARTITION BY t2.ID ORDER BY t2.EntryNum)
    FROM Table2 t2
    WHERE t2.EntryType = 'A'
) t2 ON t2.ID = t1.ID AND t2.rn = 1;

db<>fiddle

【讨论】:

以上是关于SQL 选择由 Ids 标识并由另一个表中的特定类型过滤的行列表中的所有第一项的主要内容,如果未能解决你的问题,请参考以下文章

什么是一个好的Python配置文件格式,可以轻松安全地由一个脚本编辑并由另一个脚本读取?

My SQL

sql:选择由另一列分组的两列值的计数并获得两个计数的比率

带有在单独表中定义的时间戳的 SQL EXCLUDE 记录

MySQL 从一个表中获取由另一个表的外键关联的内容

SQL(Postgres)为列表参数中的每个项目获取一行,其优先顺序由另一列指定