ROW_NUMBER()和GROUP BY有一个扭曲

时间:2013-04-29 17:31:14

标签: sql sql-server group-by row-number

我正在尝试解释在MSAccess中构建的查询,并将其转换为SQL Server的可用SQL。

以下是Access in SQL视图中的语句:

SELECT CUSTFILE.CUSTNUM, 
Last(GENPOL.eff_date) AS LastOfeff_date, 
First(GENPOL.appnum) AS FirstOfAPPNUM

FROM GENPOL INNER JOIN CUSTFILE ON GENPOL.entnum = CUSTFILE.ENTNUM

GROUP BY CUSTFILE.CUSTNUM

HAVING...

ORDER BY LastGENPOL.eff_date DESC;

我们知道First()Last()函数在SQL Server中无效且不起作用,因此我尝试使用MIN()MAX()函数,因为该表没有增量ID字段或任何内容。一个很大的问题是,例如,appnum可以在其字段中包含非常奇怪的数据,如:

 MTP-021106

OR

HMTP-271103

因此,如果插入的最后一个appnumHMTP-271103,并且像MTP-021106这样的genpol表中有较早的条目作为其appnum

将返回MTP-021106,因为M大于H

此外,eff_date可能会出现同样的问题,因为最新记录的日期可能早于最后一个记录。

Last(GENPOL.eff_date) AS LastOfeff_date,

最终,查询会为符合CUSTFILE.CUSTNUM条件的每个HAVING返回一行。

我认为可能是一个答案是使用ROW_NUMBER()函数来获取我需要的结果,但却无法使用GROUP BY语句。

表格GENPOL:

(PK)appnum, varchar(13)
eff_date, datetime
ntnum, varchar(15)

表CUSTFILE:

(PK)CUSTNUM, varchar(8)
ENTNUM, varchar(15)

样本数据

CUSTNUM | LastOfeff_date | FirstOfAppnum
MI99103 | 2013-01-01 | MTP-991103
MI99104 | 2013-01-01 | MTP-991104
MI99105 | 2013-01-01 | MTP-991105

1 个答案:

答案 0 :(得分:2)

编辑:修复了对其中一列的引用

根据您列出的内容,此类内容应该有效:

SELECT 
    cfile.CUSTNUM,
    aGENPOL.eff_date [LastOfeff_date],
    bGENPOL.appnum [FirstOfAPPNUM] 
FROM CUSTFILE cfile
CROSS APPLY (
    SELECT TOP 1 * 
    FROM (
        SELECT ROW_NUMBER() OVER(PARTITION BY entnum ORDER BY entnum) row, eff_date
        FROM GENPOL 
        WHERE entnum  = cfile.entnum        
    ) x
    ORDER BY row DESC
) aGENPOL 
CROSS APPLY (
    SELECT TOP 1 * 
    FROM (
        SELECT ROW_NUMBER() OVER(PARTITION BY entnum ORDER BY entnum) row, appnum
        FROM GENPOL 
        WHERE entnum  = cfile.entnum 
    ) y
    ORDER BY row
) bGENPOL

基本上,apply中的查询将通过按每个entnum对表进行分区,然后按行号排序(第一个升序,最后一个降序)来获取每个情境的最高记录。

由于联合查询相当复杂,我还选择使用CROSS APPLY,因为它实际上是在进行连接之前过滤掉记录。