此查询过去效果不错但现在却造成了麻烦:
SELECT
incoming.*,
prescribed.*
FROM
"CRM_DEAL_INCOMING_RANGES_M" incoming
LEFT JOIN
"CRM_DEAL_PRESCRIBED_RANGES_M" prescribed
-- join the two tables
ON prescribed.klient = incoming.klient
AND prescribed.op = incoming.op
-- make sure ranges are correct - there really is data where range_to > range_from, we just want to skip it
AND prescribed.range_from <= prescribed.range_to
AND incoming.range_from <= incoming.range_to
AND numrange(prescribed.range_from, prescribed.range_to)
&& numrange(incoming.range_from, incoming.range_to)
WHERE incoming.klient = 4;
请注意,我们确保范围边界的顺序正确。
查询以以下错误结束:ERROR: range lower bound must be less than or equal to range upper bound
。
但是,如果删除WHERE
条件,则效果很好!
问题的解释是here,工作备选方案(不包括WHERE
)的解释是here。
当规划师可以调整条件时,如何过滤掉numrange()
会阻塞的数据?
编辑:现在我只是将连接条件的第二部分从JOIN移到WHERE中,但我觉得它只是躲避计划者一段时间。
SELECT
incoming.*,
prescribed.*
FROM
"CRM_DEAL_INCOMING_RANGES_M" incoming
LEFT JOIN
"CRM_DEAL_PRESCRIBED_RANGES_M" prescribed
-- join the two tables
ON prescribed.klient = incoming.klient
AND prescribed.op = incoming.op
WHERE
incoming.klient = 4
-- make sure ranges are correct - there really is data where range_to > range_from, we just want to skip it
AND prescribed.range_from <= prescribed.range_to
AND incoming.range_from <= incoming.range_to
AND numrange(prescribed.range_from, prescribed.range_to)
&& numrange(incoming.range_from, incoming.range_to);
(正如a_horse_with_no_name正确指出的,这与原始查询有不同的语义 - 但在我的特定情况下并不重要)
答案 0 :(得分:1)
没有保证加入条款,WHERE
条款等将以任何给定的顺序执行。如果你的查询依赖于它,那就是它的错误。
在这种情况下,正确的解决方案是a CASE
expression,其中(主要)强制排序。
CASE
WHEN prescribed.range_from <= prescribed.range_to
AND incoming.range_from <= incoming.range_to
THEN numrange(prescribed.range_from, prescribed.range_to)
&& numrange(incoming.range_from, incoming.range_to)
END;
请注意,此处不需要ELSE
子句,因为CASE
如果没有子句匹配则生成NULL
,而NULL
对于WHERE
子句则为false。
这也可能会搞砸索引选择,但大多数其他方法也是如此,例如使用OFFSET 0
或(ab)使用CTE的子查询。
我认为它在反转范围内对numrange
到ERROR
有误,而不是像翻转它们或评估为null那样,正是因为它提出了这样的疑问很难写。