首页 > 解决方案 > 日期之间的过滤 Oracle SQL Developer

问题描述

我正在运行此查询以查看两个日期之间的数据,如下面的代码所示,但我只获取当前日期(如果日期是连续的)或前一天的数据(如果有日期间隔)。

我是说:

代码:

SELECT 
    C.SESSIONID,
    SUBSTR(C.ORIGINATINGNUMBER, INSTR(C.ORIGINATINGNUMBER, ':') + 1,
           INSTR(C.ORIGINATINGNUMBER, '@') - INSTR(C.ORIGINATINGNUMBER, ':') - 1) AS Origen,
    TO_CHAR(C.CALLTIMESTAMP, 'DD/MM/YYYY') AS Fecha,
    TO_CHAR(C.CALLTIMESTAMP,'HH:MI') AS Hora,
    C.DURATION AS Duracion_IVR,
    (CASE C.ENDTYPE
        WHEN 1
           THEN 'IVR'
        WHEN 2
           THEN 'Transferida'
        ELSE 'Colgada'
     END) AS Estado,
     A.SERVICIO,
     A.OPT,
     A.CONTRATO_ENVIADO,
     A.RPTA_WS_C,
     A.RPTA_WS_L,
     A.DESCRIPTIVO
 FROM 
     CDR C
 JOIN
     (SELECT DISTINCT(D.SESSIONID) AS ID,
    NVL(
    (SELECT B.MESSAGE
    FROM VPAPPLOG B
    WHERE D.SESSIONID  = B.SESSIONID
    AND B.ACTIVITYNAME = 'CAMP'
    ),' ') AS SERVICIO,
    NVL(
    (SELECT B.ACTIVITYNAME
    FROM VPAPPLOG B
    WHERE D.SESSIONID = B.SESSIONID
    AND B.MESSAGE     = 'OPC_MENU'
    ),' ') AS OPT,
    NVL(
    (SELECT B.VARVALUE
    FROM VPAPPLOG B
    WHERE D.SESSIONID = B.SESSIONID
    AND B.VARNAME     = 'CONT_ENV'
    ),' ') AS CONTRATO_ENVIADO,
    NVL(
    (SELECT B.VARVALUE
    FROM VPAPPLOG B
    WHERE D.SESSIONID  = B.SESSIONID
    AND B.VARNAME      = 'COD_RSLT_OPER'
    AND B.ACTIVITYNAME = '000'
    ),' ') AS RPTA_WS_C,
    NVL(
    (SELECT B.VARVALUE
    FROM VPAPPLOG B
    WHERE D.SESSIONID  = B.SESSIONID
    AND B.VARNAME      = 'COD_RSLT_OPER'
    AND B.ACTIVITYNAME = '001'
    ),' ') AS RPTA_WS_L,
    NVL(
    (SELECT B.VARVALUE
    FROM VPAPPLOG B
    WHERE D.SESSIONID  = B.SESSIONID
    AND B.ACTIVITYNAME = 'MSG_RPTA'
    ),' ') AS DESCRIPTIVO
  FROM VPAPPLOG D
  ) A
ON A.ID = C.SESSIONID
WHERE C.APPLICATIONNAME = 'IVR_AGBAR_Dllo'
AND C.CALLTIMESTAMP >= '16/05/18' AND C.CALLTIMESTAMP <= '17/05/18';

标签: sqloracle

解决方案


您正在将列值与字符串值进行比较,这意味着 Oracle 正在使用会话 NLS 设置将字符串隐式转换为日期或时间戳。您可以从执行计划的过滤步骤中看到:

   1 - filter("C"."CALLTIMESTAMP">=TO_TIMESTAMP('16/05/18') AND 
              "C"."CALLTIMESTAMP"<=TO_TIMESTAMP('17/05/18'))

这些隐式转换的值将时间分量设置为午夜。(它们也非常脆弱,因为它们依赖于您使用的与会话设置匹配的字符串,这并不总是在您的控制之下)。

这意味着您正在寻找 2018-05-16 00:00:00 和 2018-05-17 00:00:00 之间的值。这将在 16 日的任何时间捕获值,但只会在 17 日找到恰好在午夜的记录。

执行此操作的通常方法是范围大于或等于您的开始日期,并且小于结束日期的第二天- 这意味着您可以捕捉到当天的所有时间,但不包括当天的午夜。

AND C.CALLTIMESTAMP >= timestamp '2018-05-16 00:00:00'
AND C.CALLTIMESTAMP < timestamp '2018-05-18 00:00:00'

它将在 16 日或 17 日的任何时间查找所有记录。

如果该列实际上是日期而不是时间戳,那么您可以改用日期文字:

AND C.CALLTIMESTAMP >= date '2018-05-16'
AND C.CALLTIMESTAMP < date '2018-05-18';

如果您不想使用文字,您可以使用to_date()or to_timestamp(),使用合适的显式格式掩码。无论如何,我建议您使用完整的四位数年份,而不是 2 位数,这仍然会引起混淆(尤其是隐式转换,但也容易显式出错......)


推荐阅读