【问题标题】:oracle invalid format model with comparing dates具有比较日期的 oracle 无效格式模型
【发布时间】:2016-04-04 11:41:02
【问题描述】:

我正在尝试运行以下查询。我从参数传递日期

SELECT to_char(TIMESTAMP, 'HH24') * 1 TIMESTAMP
    ,sum(TwoG) TwoG
    ,sum(ThreeG) ThreeG
    ,sum(FourG) FourG
FROM (
    SELECT *
    FROM T_CA_Cellsdown

    UNION ALL

    SELECT *
    FROM T_CA_Cellsdown_TFVF
    )
WHERE trunc(TIMESTAMP) = trunc(to_date('03-Apr-16', 'dd-Mon-yy'))
    AND Type = 'Network'
GROUP BY to_char(TIMESTAMP, 'HH24') * 1
ORDER BY to_char(TIMESTAMP, 'HH24') * 1

查询错误:ORA-01481:无效数字格式模型

以下查询有效。我只是想将sysdate 更改为一个日期字符串,我通过用户在 php 中的输入作为参数传递。为什么它被乘以 1 我不知道,它是一个可以工作并提供所需结果的查询。

SELECT to_char(TIMESTAMP, 'HH24') * 1
    ,sum(TwoG) TwoG
    ,sum(ThreeG) ThreeG
    ,sum(FourG) FourG
FROM (
    SELECT *
    FROM T_CA_Cellsdown

    UNION ALL

    SELECT *
    FROM T_CA_Cellsdown_TFVF
    )
WHERE trunc(TIMESTAMP) = trunc(sysdate-1)
    AND Type = 'Network'
GROUP BY to_char(TIMESTAMP, 'HH24') * 1
ORDER BY to_char(TIMESTAMP, 'HH24') * 1

【问题讨论】:

  • 您的 NLS_DATE_LANGUAGE (select * from nls_session_parameters where parameter = 'NLS_DATE_LANGUAGE') 是什么? TIMESTAMP 列是什么数据类型?我猜不是日期/时间戳?最后,你为什么要乘以 1(应该不会影响任何东西,但有点奇怪)?
  • 如果您想将小时数设为数字,您可以extract(hour from timestamp)。比乘以 1 来隐式转换或使用 to_number 更简单。您的时间戳列是什么数据类型 - 听起来很明显,但它实际上是时间戳、日期还是字符串?您可以通过查询NLS_SESSION_PARAMETERS 检查 NLS 设置。当你在那里时检查 NLS_DATE_FORMAT 和 NLS_TIMESTAMP_FORMAT。 (并在问题中添加信息)。
  • 如何找到NLS_DATE_LANGUAGE? TIMESTAMP 为 DATE_TIME
  • 这通常是个坏主意@Sagi;首先是因为删除了一年中的世纪部分,其次是因为它通常会弄乱索引策略。如果某事是一个日期,那么保持它作为一个日期总是最好的。在 OP 的情况下,它们在TIMESTAMPtrunc(TIMESTAMP) 上有一个索引。在后一种情况下它被处理,在前一种更好的查询将是where timestamp >= trunc(sysdate - 1) and timestamp < trunc(sysdate)
  • 我在@Bonez 的评论中写道,尽管亚历克斯已经正确回答了它并且没关系。

标签: oracle


【解决方案1】:

问题出在最后一行:

ORDER BY to_char(TIMESTAMP, 'HH24') * 1

在 order-by 子句中,它将 TIMESTAMP 视为选择列表中的列别名,而不是表中的原始 TIMESTAMP;所以它包含一个数字,而不是时间戳。

因此,如果您有一个小时值为 13 的时间戳,比如说,您正在做

ORDER BY to_char(13, 'HH24') * 1`

...第一个参数是一个数字,您使用的是TO_CHAR() 的数字版本,而HH24 不是一个有效的格式模型。这是错误消息所说的内容。

你可以这样做:

ORDER BY TIMESTAMP;

要使用原始模式,您需要为内联视图提供表别名,然后在 order-by 中使用该别名来限定 TIMESTAMP。默认情况下,它使用列别名版本。

【讨论】:

  • 我知道出于某种原因,我将它与其他条款混为一谈,这就是为什么我在您发布您的评论之前删除了我的评论。但他发布了另一个具有相同 order by 子句的查询,效果很好。
  • @sagi - 使用相同的数据,OP 的查询得到 ORA-01481,所以我认为这不是他们真正在运行的,或者他们没有匹配的数据(不会跳闸错误),或者他们没有告诉我们的其他事情 *8-)
  • @AlexPoole sysdate -1 的查询一直有效,而且在我来之前很久就已经存在了。我试图通过传递一个日期值在网络应用程序中实现这一点,因为计算从sysdate 到减去的天数只是更多的编码工作。我假设oracle 中的trunc 指的是所选日期的午夜?
  • 我更新了问题,原始查询从未有别名,并且在 Excel 中使用 sysdate -1 进行硬编码
  • @bonez - 是的,trunc 将时间设置为午夜,你不需要用你的字符串值来做这件事,它已经是可能的夜晚了。添加的列别名破坏了查询,因为它具有优先权。但是无论之前发生了什么,这是否解决了您的新查询的问题?
【解决方案2】:

order by 最后被执行。在执行order by 时,您将在select 语句中派生一个新列timestamp。要克服它,只需按顺序使用timestamp

SELECT to_char(TIMESTAMP, 'HH24') * 1 TIMESTAMP
    ,sum(TwoG) TwoG
    ,sum(ThreeG) ThreeG
    ,sum(FourG) FourG
FROM (
    SELECT *
    FROM T_CA_Cellsdown

    UNION ALL

    SELECT *
    FROM T_CA_Cellsdown_TFVF
    )
WHERE trunc(TIMESTAMP) = trunc(to_date('03-APR-16', 'dd-Mon-yy'))
    AND Type = 'Network'
GROUP BY to_char(TIMESTAMP, 'HH24') * 1
ORDER BY TIMESTAMP  -- TIMESTAMP here refers to derived column at line 1

或者使用这个

SELECT to_char(TIMESTAMP, 'HH24') * 1 TIMESTAMP1 -- Or use different alias
    ,sum(TwoG) TwoG 
    ,sum(ThreeG) ThreeG
    ,sum(FourG) FourG
FROM (
    SELECT *
    FROM T_CA_Cellsdown

    UNION ALL

    SELECT *
    FROM T_CA_Cellsdown_TFVF
    )
WHERE trunc(TIMESTAMP) = trunc(to_date('03-APR-16', 'dd-Mon-yy'))
    AND Type = 'Network'
GROUP BY to_char(TIMESTAMP, 'HH24') * 1
ORDER BY to_char(TIMESTAMP, 'HH24') * 1

我在这里复制了这个问题。 - 这行不通。

select  to_char(TIMESTAMP, 'HH24') * 1 TIMESTAMP,sum(col1) from 
(
select sysdate-1 as TIMESTAMP,1 as col1 from dual 
union all
select sysdate-1 as TIMESTAMP,2 as col1 from dual 
)
where trunc(sysdate)=trunc(to_date('04-APR-16','Dd-Mon-YY'))
group by to_char(TIMESTAMP, 'HH24') * 1
order by to_char(TIMESTAMP, 'HH24') * 1 

但是这个语句会起作用。

select  to_char(TIMESTAMP, 'HH24') * 1 TIMESTAMP1,sum(col1) from (
select sysdate-1 as TIMESTAMP,1 as col1 from dual 
union all
select sysdate-1 as TIMESTAMP,2 as col1 from dual 
)
where trunc(sysdate)=trunc(to_date('04-APR-16','Dd-Mon-YY'))
group by to_char(TIMESTAMP, 'HH24') * 1
order by to_char(TIMESTAMP, 'HH24') * 1 --As TIMESTAMP is now reflecting the column from inner table.

【讨论】:

  • 你能解释一下为什么你的答案实际上回答了这个问题吗?很难看出您的查询和 OP 之间的差异,而且您还没有说明 OP 不正确的原因......
  • 我在答案顶部提到过。 order by is executed at last. By the time order by is executed, you are deriving an new column in select statement named timestamp
  • 我也能够复制该问题,并通过使用不同的列名作为别名来解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-21
  • 1970-01-01
  • 2012-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多