无法在多个公用表表达式中绑定标识符

Posted

技术标签:

【中文标题】无法在多个公用表表达式中绑定标识符【英文标题】:Identifier could not be bound in multiple common table expressions 【发布时间】:2020-09-15 19:47:54 【问题描述】:

我正在使用“使用 SQL 和 Excel 进行数据分析”一书中的 SQLBook 数据库来显示总发货天数高于平均发货天数的州的平均发货天数。我正在使用 2 个公用表表达式:

WITH orderDetails (days, state) 
AS(
    SELECT DATEDIFF(day, o.OrderDate, ol.ShipDate), o.State 
    FROM SQLBook.dbo.Orders o
    JOIN [SQLBook].dbo.OrderLines ol
    ON ol.OrderId = o.OrderId
)
,
/* This finds the overall average shipping days */
AvgShipping (avgShip)
AS(
    SELECT AVG(DATEDIFF(day, o.OrderDate, ol.ShipDate))
    FROM SQLBook.dbo.Orders o
    JOIN [SQLBook].dbo.OrderLines ol
    ON ol.OrderId = o.OrderId
)

SELECT
    state,
    AVG(days) AS "Average days to ship"
FROM orderDetails
GROUP BY state
HAVING AVG(days) > AvgShipping.avgShip
ORDER BY state

问题是我不断收到“无法绑定多部分标识符“AvgShipping.avgShip””错误。请让我知道这个查询的问题出在哪里。

谢谢!

【问题讨论】:

【参考方案1】:

您不会在任何地方从 AvgShpping 中进行选择。试试

WITH orderDetails (days, state) 
AS(
    SELECT DATEDIFF(day, o.OrderDate, ol.ShipDate), o.State 
    FROM SQLBook.dbo.Orders o
    JOIN [SQLBook].dbo.OrderLines ol
    ON ol.OrderId = o.OrderId
)
,
/* This finds the overall average shipping days */
AvgShipping (avgShip)
AS(
    SELECT AVG(DATEDIFF(day, o.OrderDate, ol.ShipDate))
    FROM SQLBook.dbo.Orders o
    JOIN [SQLBook].dbo.OrderLines ol
    ON ol.OrderId = o.OrderId
)

SELECT
    state,
    AVG(days) AS "Average days to ship"
FROM orderDetails
GROUP BY state
HAVING AVG(days) > (select avgShip from AvgShipping) 
ORDER BY state

【讨论】:

【参考方案2】:

您需要将AvgShipping 放在外部查询的from 子句中,这样您就可以使用它的列:

WITH ...
SELECT od.state, AVG(od.days) AS average_days_to_ship
FROM orderDetails od
CROSS JOIN AvgShipping s
GROUP BY od.state, s.avgShip
HAVING AVG(od.days) > s.avgShip
ORDER BY od.state

但我认为使用窗口函数可以更有效地完成这项任务:

select *
from (
    select state, 
        avg(datediff(day, o.orderdate, ol.shipdate)) as avg_days_state,
        1.0 * sum(sum(datediff(day, o.orderdate, ol.shipdate))) over() 
            / sum(count(*)) over() as avg_days_overall
    from  sqlbook.dbo.orders o
    inner join sqlbook.dbo.orderlines ol on ol.OrderId = o.OrderId
    group by state
) t
where avg_days_state > avg_days_overall

我们可以通过避免聚合并改用distinct 来稍微简化逻辑:

select distinct state, avg_days_state, avg_days_overall
from (
    select state, 
        avg(datediff(day, o.orderdate, ol.shipdate)) over(partition by o.state) as avg_days_state,
        avg(datediff(day, o.orderdate, ol.shipdate)) over() as avg_days_overall
    from  sqlbook.dbo.orders o
    inner join sqlbook.dbo.orderlines ol on ol.OrderId = o.OrderId
) t
where avg_days_state > avg_days_overall

【讨论】:

以上是关于无法在多个公用表表达式中绑定标识符的主要内容,如果未能解决你的问题,请参考以下文章

如何在单个 SELECT 语句中拥有多个公用表表达式?

使用具有多个语句的单个公用表表达式

是否可以使用 Python 将公用表表达式与 impala 一起使用?

存储过程——公用表表达式(CTE)

存储过程——公用表表达式(CTE)

Crystal Reports中的“多部分标识符无法绑定”与SQL表达式/子查询