日期范围内的 Oracle sql 内部联接

Posted

技术标签:

【中文标题】日期范围内的 Oracle sql 内部联接【英文标题】:Oracle sql inner join on dates range 【发布时间】:2016-02-23 14:06:20 【问题描述】:

我正在尝试编写加入 id 和日期范围的联接:

SELECT * FROM C_INVOICE CI 
INNER JOIN C_CONVERSION_RATE CCR 
    ON CCR.C_CURRENCY_ID=CI.C_CURRENCY_ID 
    AND CI.DATEINVOICED BETWEEN CCR.VALIDFROM AND CCR.VALIDTO

但我得到的结果是只加入来自

ON CCR.C_CURRENCY_ID=CI.C_CURRENCY_ID 

理论上这应该可以正常工作,我没有收到任何错误,但结果不是我想要的

编辑

--Full query
SELECT * FROM C_INVOICE CI 
INNER JOIN C_CONVERSION_RATE CCR 
    ON CCR.C_CURRENCY_ID=CI.C_CURRENCY_ID 
    AND CI.DATEINVOICED BETWEEN CCR.VALIDFROM AND CCR.VALIDTO
WHERE CI.C_INVOICE_ID='1019748';

CI.DATEINVOICED = 15-FEB-16 CI.C_CURRENCY_ID = 100

C_CONVERSION_RATE 表中有很多行,C_CURRENCY_ID = 100 但只有一行落入区间。

CI.DATEINVOICED(15-FEB-16) BETWEEN CCR.VALIDFROM(15-FEB-16) AND CCR.VALIDTO(15-FEB-16)

在这种特定情况下,CCR.VALIDFROM、CCR.VALIDTO 都等于 15-FEB-16 的同一日期,但在其他情况下,间隔可能是几天

无论如何,我期望的结果是货币 ID 和日期间隔匹配的单行。但是,我得到了货币 ID 匹配的所有行。

编辑

稍微修改了查询

SELECT 
ci.dateinvoiced,
ccr.validfrom,
ccr.validto
FROM C_INVOICE CI 
INNER JOIN C_CONVERSION_RATE CCR 
    ON CCR.C_CURRENCY_ID=CI.C_CURRENCY_ID 
    AND CI.DATEINVOICED BETWEEN CCR.VALIDFROM AND CCR.VALIDTO
WHERE CI.C_INVOICE_ID='1019748';

我得到的这个查询的结果

    15-FEB-16   07-MAR-11   29-JAN-56
    15-FEB-16   02-MAR-11   29-JAN-56
    15-FEB-16   27-MAR-11   29-JAN-56
    15-FEB-16   07-FEB-11   29-JAN-56
    15-FEB-16   18-JAN-12   29-JAN-56

ccr.validto 似乎离 56 年 1 月 29 日还有很长的路要走,该列中没有这样的日期 不知道是什么原因造成的这个问题

【问题讨论】:

CI.DATEINVOICED BETWEEN CCR.VALIDFROM AND CI.DATEINVOICED 始终为 TRUE,同一列两次... 所以你的意思是你得到BETWEEN条件不是TRUE的行? 您能否展示一些您收到的不正确数据的示例?另外,请确保您使用的查询是您在此处发布的。 第 16 年介于 11/12 和 56 之间。 如果您认为 29-JAN-56 没有日期,那么您可能会发现使用四位数年份掩码很有用;也许它不在您期望的世纪,或者您的查询仅查看 0056(取决于您的 NLS 设置)。查找该日期,和/或使用 4 位数年份重复您的查询,然后查看显示的内容。显示您查询的原始数据会很有帮助,日期再次显示全年(如果有时间,则时间不是 00:00)。 【参考方案1】:

看起来您的 C_CONVERSION_RATE 表包含许多行,其 VALIDTO 日期代表任意结束时间值 29-JAN-59(世纪未知)。如果您正在寻找相对于 DATEINVOICED 的最近有效转化率,您可能需要使用分析函数来确定下一个有效的 VALIDFROM 值:

WITH CCR AS (
  SELECT CCR.*
       , LEAD(CCR.VALIDFROM,1,CCR.VALIDTO) 
         OVER (PARTITION BY CCR.C_CURRENCY_ID 
                   ORDER BY CCR.VALIDFROM
                          , CCR.VALIDTO
         ) VALID_TO  -- note the underscore ;)
    FROM C_CONVERSION_RATE CCR
)
SELECT *
  FROM C_INVOICE CI 
 INNER JOIN CCR 
    ON CCR.C_CURRENCY_ID=CI.C_CURRENCY_ID 
   AND CI.DATEINVOICED BETWEEN CCR.VALIDFROM AND CCR.VALID_TO -- note the underscore
   AND CI.DATEINVOICED <> CCR.VALID_TO -- Make it a half open interval by not
                                       -- including the exact end date since
                                       -- it is actually the next start date.

【讨论】:

以上是关于日期范围内的 Oracle sql 内部联接的主要内容,如果未能解决你的问题,请参考以下文章

SQL从日期范围内的同一表中的不同记录中获取多个项目的总和(ORACLE)

Oracle SQL 循环遍历日期范围

ORACLE SQL - 如何检查时间是不是在特定范围内?

使用 Oracle 查找任意日期范围内的行数

sql 查询时间、日期范围内的数据

计算日期范围内的星期六和星期日的数量 - oracle [重复]