在其中一个联接上选择具有最大值的记录

Posted

技术标签:

【中文标题】在其中一个联接上选择具有最大值的记录【英文标题】:Selecting a record with max value on one of the joins 【发布时间】:2015-05-13 11:53:33 【问题描述】:

我有三个相关的表,需要根据第三个表中的值(序列号)选择显示两个表中数据的行。我只对序列号的最大值感兴趣。我已经尝试过在 *** 上建议的多种解决方案,但我仍然无法理解这一点。

此处提供了我的表的示例代码,其中包含所有值的直接 SELECT:http://sqlfiddle.com/#!6/6b8f7/4/0

我的最终目标是获得这样的表格:

reference   groupname   serialnum
C:123       Group2      3
C:125       Group1      4
C:126       Group1      1

使用 LIMIT 排序似乎不起作用。 有什么想法可以解决这个问题吗?

DDL + DML 用于示例数据:

CREATE TABLE pm_process
    ([pm_guid] int, [Descr] varchar(4), [usr_newref] varchar(5))
;

INSERT INTO pm_process
    ([pm_guid], [Descr], [usr_newref])
VALUES
    (11111, 'aaaa', 'C:123'),
    (22222, 'bbbb', 'C:125'),
    (33333, 'cccc', 'C:126')
;


CREATE TABLE tps_group
    ([tps_title] varchar(6), [tps_guid] int)
;

INSERT INTO tps_group
    ([tps_title], [tps_guid])
VALUES
    ('Group1', 99999),
    ('Group2', 88888)
;


CREATE TABLE pm_process_assignment
    ([pm_group_guid] int, [pm_process_guid] int, [pm_serial_number] int)
;

INSERT INTO pm_process_assignment
    ([pm_group_guid], [pm_process_guid], [pm_serial_number])
VALUES
    (99999, 11111, 1),
    (99999, 11111, 2),
    (88888, 11111, 3),
    (88888, 22222, 1),
    (99999, 22222, 2),
    (88888, 22222, 3),
    (99999, 22222, 4),
    (99999, 33333, 1)
;

【问题讨论】:

RIGHT JOIN... 很少有人能理解这些。拯救世界并改用 LEFT JOIN。 SQL Server/T-SQL 不使用limit,而是使用top @jarlh:这只是角度问题。你可以通过镜子看屏幕,这有帮助:-) @Pawzik:链接到 sql fiddle 非常好,它可以为想要回答您问题的人节省大量时间和精力。但是,您也应该在消息中包含 DDL 和 DML,因为 sql fiddle 会遭受很多停机时间。 @ZoharPeled - 注意! 【参考方案1】:

在 SQL Server 中,最简单的方法可能是使用APPLY

SELECT p.usr_newref as reference,
       pag.tps_title as groupname,
       pag.pm_serial_number as serialnum
FROM pm_process p OUTER APPLY
     (SELECT TOP 1 pa.pm_serial_number, g.tps_title
      FROM pm_process_assignment pa JOIN
           tps_group g
           ON g.tps_guid = pa.pm_group_guid
      WHERE pa.pm_process_guid = p.pm_guid
      ORDER BY pm_serial_number DESC
     ) pag

Here 是 SQL 小提琴。

【讨论】:

@Gordon:我已将链接添加到相关的 technet 页面。希望你不介意...【参考方案2】:

您可以使用ROW_NUMBER() 来定位每个reference 分区内具有最大serialnum 的记录。然后,在外部查询中,只选择这些记录:

SELECT reference, groupname, serialnum
FROM (
SELECT
  pm_process.usr_newref as reference,
  pm_assignment_group.tps_title as groupname,
  process_assignments.pm_serial_number as serialnum,
  ROW_NUMBER() OVER (PARTITION BY pm_process.usr_newref 
                     ORDER BY process_assignments.pm_serial_number DESC) AS rn
FROM
  tps_group  pm_assignment_group 
  RIGHT OUTER JOIN pm_process_assignment  process_assignments 
    ON (pm_assignment_group.tps_guid=process_assignments.pm_group_guid)
  RIGHT OUTER JOIN pm_process 
    ON (process_assignments.pm_process_guid=pm_process.pm_guid)
) t
WHERE t.rn = 1

SQL Fiddle Demo

【讨论】:

这也给了我想要的东西。谢谢!【参考方案3】:

使用RANKCTE。它会处理多个 pm_serial_number 具有相同值的情况。

WITH RankTable AS
(

    SELECT *, RANK() OVER (
        PARTITION BY usr_newref 
        ORDER BY pm_serial_number DESC) AS R
    FROM pm_process
    LEFT JOIN pm_process_assignment 
        ON pm_process_assignment.pm_process_guid = pm_process.pm_guid
    LEFT JOIN tps_group 
        ON tps_group.tps_guid = pm_process_assignment.pm_group_guid
)
SELECT usr_newref, tps_title, pm_serial_number 
FROM RankTable 
WHERE RankTable.R = 1

【讨论】:

以上是关于在其中一个联接上选择具有最大值的记录的主要内容,如果未能解决你的问题,请参考以下文章

在多个表上选择最大值,而不计算两次

连接 2 个表,在另一个表上选择最高值

如何在 SQL 中的一个字段上选择不重复的记录?

MYSQL 在一列上选择两个值

Postgresql:在不返回任何记录的视图上选择查询

在先前选择的复选框的基础上选择复选框