【问题标题】:Right join isn't pulling in all rows from right table右连接没有从右表中提取所有行
【发布时间】:2021-04-21 22:47:08
【问题描述】:

我在 Microsoft SQL Server 数据库中有两个用于呼叫中心的表,fact_queue,其中包含已接收呼叫的数量,以及 dim_interval,用于将间隔号 (0-95) 转换为时间戳 (例如 07:15-07:30)。它是这样设置的,因此您可以轻松更改正在提取的时区数据。

我正在尝试获得一个结果,该结果将显示所有 96 个间隔,无论是否有呼叫,但它没有按预期工作。

以下是表格中的示例:

事实队列

date_id queue_id interval_id calls_offered
7780 40 0 1
7780 40 2 5
7780 40 3 6
7780 40 5 10

Dim_Interval

interval_id interval_name
0 00:00 - 00:15
1 00:15 - 00:30
2 00:30 - 00:45
3 00:45 - 01:00
-- --
95 23:45 - 24:00

我已经使用了几个查询变体,我相信以下应该可以工作,但它不是

SELECT dim_interval.interval_name
      ,fact_queue.offered_calls
FROM dim_interval
RIGHT JOIN fact_queue
  ON fact_queue.interval_id = dim_interval.interval_id
WHERE fact_queue.date_id= '7780'
  AND fact_queue.queue_id = '40'
ORDER BY dim_interval.interval_id

这只会导致

interval_name calls_offered
00:00 - 00:15 1
00:30 - 00:45 5
00:45 - 01:00 6
01:15 - 01:30 10

但我想要的是

interval_name calls_offered
00:00 - 00:15 1
00:15 - 00:30 null
00:30 - 00:45 5
00:45 - 01:00 6
01:00 - 01:15 null

为什么查询不起作用?如果重要的话,我使用的是 DBeaver 版本 21.0.3.202104181339

【问题讨论】:

  • 您需要将left join 加入Fact_Queue,在加入时包含where 条件。
  • 每个right join 都可以表示为left join,应该是这样,因为大多数人觉得它更容易理解

标签: sql-server join dbeaver


【解决方案1】:

在 sn-p dim_interval JOIN fact_queue 中,您将维度表放在左侧,而不是右侧。由于您需要所有维度表的行,这意味着您需要左外连接...

FROM dim_interval LEFT JOIN fact_queue

这只会让你走到一半,因为 WHERE 子句是在连接之后应用的。这意味着 WHERE 子句将过滤掉具有 NULL 的结果。

所以,你需要在加入期间进行过滤...

SELECT dim_interval.interval_name
      ,fact_queue.offered_calls
FROM dim_interval
LEFT JOIN fact_queue
  ON fact_queue.interval_id = dim_interval.interval_id
  AND fact_queue.date_id= '7780'
  AND fact_queue.queue_id = '40'
ORDER BY dim_interval.interval_id

有些人喜欢在加入之前进行过滤,但这不是必需的,实际上会产生相同的执行计划......

SELECT dim_interval.interval_name
      ,fact_queue.offered_calls
FROM dim_interval
LEFT JOIN (
    SELECT *
    FROM fact_queue
    WHERE date_id= '7780'
    AND queue_id = '40' 
) AS fact_queue
  ON fact_queue.interval_id = dim_interval.interval_id
ORDER BY dim_interval.interval_id

【讨论】:

  • 谢谢@MatBailie 我翻转了桌子并做了SELECT dim_interval.interval_name ,fact_queue.offered_calls FROM mart.fact_queue fact_queue RIGHT JOIN mart.dim_interval dim_interval ON fact_queue.interval_id = dim_interval.interval_id AND fact_queue.date_id= '7780' AND fact_queue.queue_id = '40' ORDER BY dim_interval.interval_id 所以我现在得到了我想要的。为什么AND fact_queue.date_id= '7780' AND fact_queue.queue_id = '40' 必须是连接的一部分才能起作用,而不是 WHERE 子句的一部分?
  • @SpencerRay - 因为 WHERE 子句在连接之后应用到值,否则它们将出现在结果中。到那时,您将在 fact_queue 列中拥有带有 NULL 的行,其中没有关于 OUTER JOIN 到维度记录的事实记录。由于 NULL 从不等于任何内容,因此 WHERE 子句将排除该结果行。实际上,在 WHERE 子句中使用该过滤器会将 OUTER JOIN 重新转换为 INNER JOIN。因此,您需要在加入前或加入期间过滤事实表。
  • 另外,根据另一条评论,RIGHT JOIN 并不常用。虽然没有技术上的理由来避免它们,但出于可维护性和可读性的考虑,使用 LEFT JOIN 通常更清晰且更受欢迎。如果 LEFT JOIN 符合逻辑,则应优先于 RIGHT JOIN。
  • 感谢您向我解释!没有点击,问题就解决了!
猜你喜欢
  • 2021-04-12
  • 2015-07-27
  • 1970-01-01
  • 1970-01-01
  • 2014-05-03
  • 2013-11-15
  • 1970-01-01
  • 2023-03-20
  • 1970-01-01
相关资源
最近更新 更多