5

我正在使用在 Oracle SQL 数据库之上运行的业务对象。我无权访问 PL 或任何类型的 SQL 命令行,也无权访问数据库。我只能将查询作为单个命令运行,需要输出一组定义的列。

我能够从用户提示中获取数据,这些数据在 SQL 中显示为:

@variable('Prompt1')

例如我可以说:

SELECT
    A.SomeDate
FROM
    A
WHERE
    A.SomeDate BETWEEN @variable('Start') AND @variable('End Date')

这很容易。它运行;要求用户输入一些日期;然后返回它们之间的所有匹配项(包括)。

然而,问题是,用户将使用 Business Objects 的“Infoview”系统来运行查询,并且提示系统会显示一个日期选择器 - 默认情况下包括日期的时间部分(“01/01/2016 12 :00:00 AM”)。

如果用户不删除时间部分,如果 SomeDate 值超出所选时间,可能会导致记录丢失。例如,如果我想获取 TODAY 的所有记录,那么从技术上讲,我需要 00:00:00(午夜)和 23:59:59 之间的所有记录。

我真正想做的是在查询变量周围使用 TRUNC ,如下所示:

WHERE
    A.SomeDate BETWEEN TRUNC(@variable('Start')) AND TRUNC(@variable('End Date'))

...但是这会导致编译错误:“不一致的数据类型:预期的 DATE 得到了 NUMBER”。我不知道为什么 Oracle 在编译之前会将提示视为数字数据类型。

有谁知道我如何获取@variable 值并将其转换为我能够截断为日期值的东西?

因此,我试图找出解决方法。我想到的一件事是我是否可以使用提示变量并将其显式转换为日期,使用 TO_DATE

编辑:有人向我指出,TRUNC 将无效,因为“12:00:00 AM”已经是午夜了。因此,我认为我误解了 TRUNC。它似乎将其截断到午夜:而我认为它只是完全删除了日期的时间部分,这意味着将在 00:00:00 和 23:59:59 之间的任何时间返回匹配项。

我真正想要的是:如果 SomeDate 有一个时间部分,例如 11:03,那么当结束日期提示仅指定日期时,我如何确保将其包含在内?

4

3 回答 3

1

尝试一起使用TO_CHAR()and TO_DATE()

WHERE
A.SomeDate > TO_DATE(TO_CHAR(@variable('Prompt1'),'ddmmyyyy'),'ddmmyyyy')
于 2016-08-17T13:58:20.567 回答
1

如果您想匹配SomeDateStart 上 00:00:00 和 End 上 23:59:59 之间的值,您可以调整结束日期以使用该时间而不是默认午夜,或者使用范围而不是between

WHERE
    A.SomeDate >= @variable('Start')
AND
    A.SomeDate < @variable('End Date') + 1

使用Oracle 日期算法为您提供变量值之后的第二天,因此如果用户选择“01/01/2016 12:00:00 AM”作为开始日期和结束日期,他们将评估为 2016-01-01 + 100 :00:00 和 2016-01-02 00:00:00 分别。如果您愿意,可以使用该语法。interval

通过使用小于作为上限,您可以获得SomeDate大于或等于开始日期 2016-01-01 00:00:00 且小于调整结束日期 2016-01-02 00:00:00 的所有记录- 这与 2016-01-01 23:59:59 之前的说法相同。(或者,如果您有一个具有亚秒精度的时间戳列,最高可达 23:59:59.999...)。

如果解析器假定变量将是一个字符串,但它实际上是一个日期——导致“数据类型不一致”错误——那么你可以将它转换为一个日期以满足解析器的要求:

WHERE
    A.SomeDate >= CAST(@variable('Start') AS DATE)
AND
    A.SomeDate < CAST(@variable('End Date') AS DATE) + 1

或者,如果它实际上以您显示的格式作为字符串传递,您可以显式转换它:

WHERE
    A.SomeDate >= TO_DATE(@variable('Start'), 'DD/MM/YYYY HH:MI:SS AM')
AND
    A.SomeDate < TO_DATE(@variable('End Date'), 'DD/MM/YYYY HH:MI:SS AM') + 1

...确保您的格式正确;从您的示例来看,它可能是 DD/MM/YYYY 或 MM/DD/YYYY。

于 2016-08-17T14:27:04.717 回答
0

首先,您的问题不是来自提示值中的时间值,而是来自SomeDate. 摆脱它(使日期等于午夜)将解决问题。

如果您可以选择修改 Universe,最好的选择是创建另一个对象。我假设您有一个名为的对象SomeDate,其 SQL 为a.somedate. 创建另一个对象,让我们用* **SomeDateOnly的定义来调用它。trunc(a.somedate)

由于SomeDateOnly将始终是午夜值,因此您可以在提示中使用 Equal To,这将产生如下 SQL:

trunc(a.somedate) = @variable('Prompt1')

当由 WebI 呈现时,将产生:

trunc(a.somedate) = '16-08-2016 00:00:00'

这将返回a.somedate2016 年 8 月 16 日 00:00:00 到 2016 年 8 月 16 日 23:59:59 之间的所有记录。

当然,您可以使用 BETWEEN 来选择日期范围:

 trunc(a.somedate) between @variable('Start Date') and @variable('End Date')

即使你无权访问宇宙,你仍然可以通过修改 WebI 生成的 SQL 来使用上述语法。(无论如何,我假设这就是你一直在做的事情)。

如果以上内容对您有用,那么以下内容无关紧要,但我还是想解决它:

您收到“无效号码”错误的原因是 WebI 为 SQL 格式化日期的方式。如果您的查询中有此字符串:

A.SomeDate = TRUNC(@variable('Prompt1'))

然后 WebI 会将 @variable(...) 替换为日期字符串,并在将其发送到 Oracle 之前将其呈现为以下内容:

A.SomeDate = TRUNC('16-08-2016 00:00:00')

当然,这对 TRUNC() 函数没有意义,因为没有什么可以告诉它它实际上是一个日期值。

可以 to_date先提示,但必须使用正确的日期格式。WebI 将每个会话的 nls_date_format 设置为非默认格式,因此您必须使用:

A.SomeDate = TRUNC(to_date(@variable('Prompt1')),'dd-mm-yyyy hh24:mi:ss')

但同样,这无关紧要,因为您需要 trunc somedate,而不是提示响应值。


*更好的是,重命名SomeDateSomeDateTime,并命名新对象SomeDate

**这很常见 - 同一个源字段有多个对象。有时您需要日期/时间值(用于列出特定交易),但有时您只需要日期(用于按日期计算交易)。因此,两者都可用是非常有用的。

于 2016-08-18T12:52:26.590 回答