sql - 日期之间的过滤 Oracle SQL Developer
问题描述
我正在运行此查询以查看两个日期之间的数据,如下面的代码所示,但我只获取当前日期(如果日期是连续的)或前一天的数据(如果有日期间隔)。
我是说:
如果间隔 (16/05/18 - 17/05/18) 仅返回 16/05/18 的数据。
如果区间是 (16/05/18 - 18/05/18) 仅返回区间 (16/05/18 - 17/05/18) 的数据
代码:
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';
解决方案
您正在将列值与字符串值进行比较,这意味着 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 位数,这仍然会引起混淆(尤其是隐式转换,但也容易显式出错......)
推荐阅读
- java - James 邮件服务器出现问题:有时无法从 gmail 接收电子邮件
- python - 在python中用for循环替换csv列
- javascript - 在 Codeigniter 中使用 mpdf 完成 Pdf 生成时隐藏加载器
- android - How to change TextView background color while it's pressed down?
- python - sns 在使用 cloudformation 创建时无法触发 lambda
- python - 尝试为大多数重叠点创建颜色图
- javascript - 如何使用 jquery 在表格行中动态创建的选择框中填充数据
- php - Toogle 设备工具栏
- java - 使用 PDFBOX jar 加载后 PDF 正在发生变化
- python - 如何在python pandas的for循环中将分类数据转换为数值数据