从链接到 Oracle 的 SQL Server 编写 SQL 查询时如何指定日期文字?

问题描述 投票:0回答:3

我有一个链接到 Oracle 12.1 数据库的 SQL Server 12.0 数据库。

我想在 SQL Server 数据库中创建一个视图,该视图返回按日期筛选的 Oracle 表中的数据。 Oracle 表在日期列上有一个索引。

成功运行的查询是:

select * from ORADB..SCHEMA.MYTABLE where MYDATE >= '20140701';

但是运行速度非常慢。我认为这是因为比较是在 SQL Server 中进行的,所以每一行都会被返回。

如果我去:

DECLARE @earliest date = '20140701';
select * from ORADB..SCHEMA.MYTABLE where MYDATE >= @earliest;

然后它运行得很快,大概是因为条件正在传递给 Oracle,因此正在使用表上的 Oracle 索引。

我的问题是我想创建一个视图。我找不到使用第二个版本的代码来创建视图的方法。如果我简单地这样做:

create myview as select * from ORADB..SCHEMA.MYTABLE where MYDATE >= '20140701';

然后它运行缓慢。

SQL Server 将传递给 Oracle 的日期文字是否有其他格式,或者是否有其他解决方案?我还想知道这是否与创建 Oracle 链接时使用的参数有关。作为参考,它们是:

USE [master]
GO
EXEC master.dbo.sp_addlinkedserver @server = N'ORADB', @srvproduct=N'Oracle', @provider=N'OraOLEDB.Oracle', @datasrc=N'DPDB'
EXEC master.dbo.sp_addlinkedsrvlogin @rmtsrvname=N'ORADB',@useself=N'False',@locallogin=NULL,@rmtuser=N'MYUSER',@rmtpassword='#######'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'collation compatible', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'data access', @optvalue=N'true'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'dist', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'pub', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'rpc', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'rpc out', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'sub', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'connect timeout', @optvalue=N'0'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'collation name', @optvalue=null
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'lazy schema validation', @optvalue=N'false'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'query timeout', @optvalue=N'0'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'use remote collation', @optvalue=N'true'
GO
EXEC master.dbo.sp_serveroption @server=N'ORADB', @optname=N'remote proc transaction promotion', @optvalue=N'true'
GO

编辑:我刚刚发现一个非常相似的问题:强制 SQL Remote 查询远程过滤而不是本地

sql sql-server oracle date-formatting
3个回答
35
投票

我更喜欢 ODBC 格式:

--DateTime
SELECT {ts'2015-09-20 12:30:00'}
--Time (however this comes with "today"-time)
SELECT {t'12:30:00'}
--Date
SELECT {d'2015-09-20'}
GO

简单的日期文字与文化无关......

SET LANGUAGE ENGLISH;
SELECT CAST('2014-09-13' AS DATETIME);
GO
SET LANGUAGE GERMAN;
SELECT CAST('2014-09-13' AS DATETIME);--ERROR: there's no month "13"
GO

但它适用于目标类型

DATE
(这种差异相当奇怪......):

SET LANGUAGE ENGLISH;
SELECT CAST('2014-09-13' AS DATE);
GO
SET LANGUAGE GERMAN;
SELECT CAST('2014-09-13' AS DATE);--works
GO

感谢 lad2025,为了完整性,我想添加“完整”ISO 8601,它工作得很好:

SET LANGUAGE ENGLISH;
SELECT CAST('2014-09-13T12:30:00' AS DATETIME);
GO
SET LANGUAGE GERMAN;
SELECT CAST('2014-09-13T12:30:00' AS DATETIME);
GO

7
投票

我建议使用 @lad2025 建议的完整 ISO 8601 格式:

'2017-10-06T14:57:23'

这优于@Shnugo 建议的 ODBC 格式。

至少在 SQL Server 2014 中,ODBC 格式不适用于 1753-01-01 之前的日期(例如,那些超出旧 DATETIME 数据类型范围的日期),而 ISO 8601 格式则适用。

要亲自测试这一点,请尝试以下查询:

--This will work
DECLARE @DateISO DATE = '0001-01-01T00:00:00';
SELECT @DateISO;

--This will also work
DECLARE @DatetimeISO DATETIME2 = '0001-01-01T00:00:00';
SELECT @DatetimeISO;

--This will not work
DECLARE @DateODBC DATE = {D '0001-01-01'};
SELECT @DateODBC;

--This will also not work
DECLARE @DatetimeODBC DATETIME2 = {ts '0001-01-01 00:00:00'};
SELECT @DatetimeODBC;

即使您认为您正在处理的日期不会早于 1753 年,这也是一个好习惯。我在考虑设置日历表以在查询中引用时遇到了这个问题。


3
投票

如果查询在 Oracle 数据库上运行,那么我建议使用 ANSI 日期文字,它使用固定格式 YYYY-MM-DD

例如,

DATE '2015-10-20'

在 Oracle 中,

'20140701'
字符串,而不是DATE。您可能很幸运地看到“隐式数据类型转换”,并根据“客户端的特定于区域设置的 NLS 设置”获得结果。您应该始终避免它,并显式地将字符串转换为日期以进行日期比较。
© www.soinside.com 2019 - 2024. All rights reserved.