使用row_number()OVER(PARTITION BY)的列名无效

时间:2016-08-03 16:32:26

标签: sql sql-server database inner-join

我正在尝试加入两个TBL_CONTACTTBL_PHONE个表。

TBL_PHONE表包含具有多个电话号码的联系人的重复行,因此我正在对这些行进行分区并尝试仅选择第一个实例。

这是我的代码:

SELECT
    (CONTACT.CONTACTID),
    (CONTACT.FULLNAME),
    (PHONE.contactid),
    (PHONE.numberdisplay),
    (row_number() OVER(PARTITION BY PHONE.Contactid ORDER BY PHONE.Contactid)) prn
FROM
    "ACT2015Demo"."dbo"."TBL_CONTACT" AS CONTACT
INNER JOIN
    TBL_PHONE AS PHONE
    ON CONTACT.Contactid = PHONE.Contactid
WHERE
    CAST(Editdate AS DATE) = CAST(GETDATE() AS DATE)

这给出了以下内容:

CONTACTID   FULLNAME   CONTACTID    NUMBERDISPLAY   PRN
1001        Name1      1001         Tel1001 1       1
1001        Name1      1001         Tel1001 2       2
1002        Name2      1002         Tel1002 1       1
1003        Name3      1003         Tel1003 1       1
1003        Name3      1003         Tel1003 2       2
1003        Name3      1003         Tel1003 3       3

然后我想使用PRN列将输出限制为只有PRN = 1的行。我尝试了以下内容,因为这对我来说在过去不太复杂的连接中起作用了:

SELECT
    (CONTACT.CONTACTID),
    (CONTACT.FULLNAME),
    (PHONE.contactid),
    (PHONE.numberdisplay),
    (row_number() OVER(PARTITION BY PHONE.Contactid ORDER BY PHONE.Contactid)) prn
FROM
    "ACT2015Demo"."dbo"."TBL_CONTACT" AS CONTACT
INNER JOIN
    TBL_PHONE AS PHONE
    ON CONTACT.Contactid = PHONE.Contactid AND PRN = 1
WHERE
    CAST(Editdate AS DATE) = CAST(GETDATE() AS DATE)

但是,这会为PRN提供无效的列名错误?我也尝试将PRN = 1作为WHERE的一部分使用,并出现同样的错误。

如何让PRN作为列名工作并限制输出?

3 个答案:

答案 0 :(得分:2)

有些人对SQL有点奇怪和混淆是你在select-list中定义的列别名不能在FROM子句或WHERE子句中引用。

这是令人困惑的,因为列别名似乎在查询的早期定义(因为select-list在FROM子句之前)。但语法的顺序不是执行顺序。

您可以通过将查询作为派生表子查询运行来解决此问题:

SELECT * 
FROM (
    SELECT
        CONTACT.CONTACTID,
        CONTACT.FULLNAME,
        PHONE.contactid,
        PHONE.numberdisplay,
        ROW_NUMBER() OVER(PARTITION BY PHONE.Contactid ORDER BY PHONE.Contactid) AS PRN
    FROM
        "ACT2015Demo"."dbo"."TBL_CONTACT" AS CONTACT
    INNER JOIN
        TBL_PHONE AS PHONE
        ON CONTACT.Contactid = PHONE.Contactid
    WHERE
        CAST(Editdate AS DATE) = CAST(GETDATE() AS DATE)
    ) AS DerivedTable
WHERE PRN = 1

PS:MySQL不支持最高5.7版本的窗口函数。已宣布此功能正在开发中,希望它将在MySQL 8中准备好。我想您可能已经错误地标记了您的问题。

您使用架构限定符dbo这让我觉得您使用的是Microsoft SQL Server或Sybase,这是正确的吗?

答案 1 :(得分:1)

我尝试了以下内容,因为这对我来说在过去不太复杂的连接中起作用了......你尝试过的方法也不会用于简单的连接。你必须使用Derived table或CTE

Select 
*
from
(
SELECT
    (CONTACT.CONTACTID) as concontactid,
    (CONTACT.FULLNAME),
    (PHONE.contactid),
    (PHONE.numberdisplay),
    (row_number() OVER(PARTITION BY PHONE.Contactid ORDER BY PHONE.Contactid)) prn
FROM
    "ACT2015Demo"."dbo"."TBL_CONTACT" AS CONTACT
INNER JOIN
    TBL_PHONE AS PHONE
    ON CONTACT.Contactid = PHONE.Contactid 
WHERE
    CAST(Editdate AS DATE) = CAST(GETDATE() AS DATE)
) as b
where prn=1

答案 2 :(得分:1)

row_number()OVER(PARTITION BY)子句的复合关键字段集出现在连接的两个表中时,也会发生此错误。无论排列或重新排列别名如何,错误都不会消失。要解决此问题,必须在内联临时表中重命名连接表中具有相同名称的键列,如下所示。 更改此内容:

    INNER JOIN
    TBL_PHONE AS PHONE
    ON CONTACT.Contactid = PHONE.Contactid 
    ... some other col_names 
    etc. ...

到此:

    INNER JOIN (
        SELECT
            Contactid as PK_Contactid,
            ... some other col_names as PK_col_names,
            etc. ...
        FROM TBL_PHONE
        ) AS PHONE
    ON CONTACT.Contactid = PHONE.PK_Contactid
    ... some other col_names 
    etc. ...

NB。不要在 row_number()OVER(PARTITION BY)中使用表别名作为任何 col_names 的前缀条款。为我工作。