【问题标题】:Joining tables based on the maximum id根据最大 id 连接表
【发布时间】:2023-03-19 18:24:01
【问题描述】:

我发现三个问题似乎都在问一个相似的问题:

Getting max value from rows and joining to another table

Select only rows by join tables max value

Joining tables based on the maximum value

但是当最大值位于 id 或索引字段本身时,我很难弄清楚如何准确地连接表,只保留其中一个表的最大行。

我正在寻找一个只需要连接的答案,因为这将允许解决方案在一个生成查询的工具中工作,很容易让它生成相应的连接,尽管子查询也可能是可行的用更多的努力。我发现下面的答案特别有趣:

SELECT DISTINCT b.id, b.filename, a1.name
FROM a a1
JOIN b
  ON b.id = a1.id
LEFT JOIN a a2
  ON a2.id = a1.id
  AND a2.rank > a1.rank
WHERE a2.id IS NULL

但是,在我的情况下,排名列也是索引,例如“ID”。我不能同时比较相等和大于,因为它们永远不会同时为真!

此外,可能使情况复杂化的是,我需要的典型查询可能会连接多个表(3-5 并不少见)。因此,作为我的查询的简化示例:

SELECT
    table1.field1, table1.field2, table1.field3,
    table2.field1, table2.field2, table2.field3,
    table3.field1, table3.field2, table3.field3,
    table4.field1, table4.field2, table4.field3
FROM table1
INNER JOIN table2 ON
    table1.field1 = table2.field1
    AND table1.field2 = table2.field2
    AND table2.field3 < 0
INNER JOIN table3 ON
    table2.field1 = table3.field1
    AND table2.field4 = table3.field4
INNER JOIN table4 ON
    table1.field1 = table4.field1
    AND table1.field2 = table4.field2

我想要做的是通过仅获取所有其他字段的每个唯一组合的具有最大 id 的行(例如 MAX(table3.id))来消除 table3 中的重复项。也就是说,上面的查询返回的是这样的:

+-------+-------+-------+---------+
| table1| table2| table4|table3   |
+-------+-------+-------+---------+
|  A    |   A   |   A   | 1,...   |
|  A    |   A   |   A   | 2,...   |
|  A    |   A   |   A   | 3,...   |
|  A    |   A   |   A   | MAX2,...|
|  B    |   B   |   B   | 1,...   |
|  B    |   B   |   B   | 2,...   |
|  B    |   B   |   B   | 3,...   |
|  B    |   B   |   B   | MAX2,...|
+-------+-------+-------+---------+

(我只是使用 A 和 B 来表示我正在谈论针对特定行集的 table1、table2 和 table4 中的字段的所有相同值。)

我想把它简化为:

+-------+-------+-------+---------+
| table1| table2| table4|table3   |
+-------+-------+-------+---------+
|  A    |   A   |   A   | MAX1,...|
|  B    |   B   |   B   | MAX2,...|
+-------+-------+-------+---------+

【问题讨论】:

  • SELECT table1.id, MAX(table3.field3) FROM (&lt;query from above&gt;) GROUP BY table1.id 怎么样?
  • @500-InternalServerError SELECT table1.field1, table1.field2, table1.field3, table2.field1, table2.field2, table2.field3, table3.field1, table3.field2, table3.field3, table4.field1, table4.field2, table4.field3 table1.id, MAX(table3.field3) FROM (&lt;query from above&gt;) GROUP BY table1.id ?
  • 样本数据最好使用DDL + DML。请edit您的问题包括它,您当前的尝试和您想要的结果。更多详情,read this.
  • @Michael 我认为应该是 SELECT table1.columns、table2.columns、table4.columns、MAX(table3.columns) 和 GROUP BY table1.columns、table2.columns、table4.columns。如果您不聚合 table3 中的所有列,则应将这些列放入 GROUP BY
  • @DávidLaczkó 我的理解是,某些数据库不能保证 MAX 和 GROUP BY 可以很好地协同工作以从同一行返回数据。例如,如果表 3 的 id、field1 和 field2 具有“3, A, RED”、“4, B, BLUE”、“5, C, WHITE”,则 MAX(id) 将返回 5,但 field1 和 field2值不保证是“C”和“WHITE”...

标签: sql sql-server tsql join


【解决方案1】:

您可以添加派生表以将TABLE3 中的匹配行减少到每组一个。另一种方法是使用窗口函数,但您只要求JOIN

SELECT
    table1.field1, table1.field2, table1.field3,
    table2.field1, table2.field2, table2.field3,
    table3.field1, table3.field2, table3.field3,
    table4.field1, table4.field2, table4.field3
FROM table1
INNER JOIN table2 ON
    table1.field1 = table2.field1
    AND table1.field2 = table2.field2
    AND table2.field3 < 0
INNER JOIN table3 ON
    table2.field1 = table3.field1
    AND table2.field4 = table3.field4

--here is the added derived table. Change column names as needed
INNER JOIN (select UID, ID = max(ID) from Table3 group by UID) x
    on x.UID = table3.UID and x.mx = table3.ID

INNER JOIN table4 ON
    table1.field1 = table4.field1
    AND table1.field2 = table4.field2

或者,也许……像下面这样。这实际上取决于您的架构,而这很难通过示例数据来理解。

INNER JOIN (select field1, field4, mx = max(ID) from Table3 group by field1, field4) x
    on x.field1 = table3.field1 and x.field4 = table3.field4 and x.mx = table3.ID

这是一个例子。您会注意到最后三列对是相同的。您只需要最后一个,即该分组的 max(id)。使一行相对于您的其余数据(不是您的主键,而是您加入的数据)唯一的原因是您希望在派生表和连接条件中包含的内容。

declare @table table (id int identity(1,1), f1 char(1), f2 char(1))
insert into @table
values
('a','b'),
('a','c'),
('a','a'),
('b','b'),
('b','b'),
('b','b')

select * from @table

select t1.*
from @table t1
inner join 
    (select f1, f2, mx = max(id) from @table group by f1, f2) t2 on
    t1.f1 = t2.f1
    and t1.f2 = t2.f2
    and t1.id = t2.mx

【讨论】:

  • 抱歉,有点糊涂了……我觉得UID是表的id字段,ID是最大值,那应该是ID=max(UID)from Table3 group by UID
  • UID 可能是一个糟糕的名称选择。所以,这里的 UID 将是一个外键(很可能是你的其他表。所以,如果你需要它们,要么是 field1 要么 field4 ......或者两者兼而有之。ID 将是你想要最大值的列。如果你想要最大值(ID) 对于每个 field1 / field4 对,然后只需将 UID 替换为这两列并按它们分组并将它们添加到连接子句中(我将在编辑的底部添加一个 sn-p)
  • 我在派生表中有table2,它应该是table3。你正在做一个自我内连接是限制行的关键。并且 x.id 应该是 x.mx 因为那是我的别名。
  • 是的,对不起,我没有真正记录架构,我正在尝试解决一般情况,因为我有几个要解决的查询,所以你可以假设有一个“id”字段,它是索引(例如 INTEGER PRIMARY KEY 或其他)和任意编号的字段“field1”、“field2”等,直到每个表都有许多字段。如果我理解自联接中的选择应该(仅)包括上一个表加入的所有字段?
  • 好的,所以我将派生表修改为在之前加入的所有字段“table3”上进行自联接,并且......我现在得到了预期的行数。看起来不错,只是需要做一些最终验证,我会接受。
猜你喜欢
  • 2010-12-24
  • 1970-01-01
  • 2011-09-30
  • 2020-12-11
  • 1970-01-01
  • 2015-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多