web-dev-qa-db-fra.com

Comment spécifier un littéral de date lors de l'écriture d'une requête SQL à partir de SQL Server liée à Oracle?

J'ai une base de données SQL Server 12.0 liée à une base de données Oracle 12.1.

Je souhaite créer une vue dans la base de données SQL Server qui renvoie les données d'une table Oracle filtrée par date. La table Oracle a un index sur la colonne de date.

Une requête qui fonctionne avec succès est:

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

Cependant cela fonctionne très lentement. Je suppose que c'est parce que la comparaison a lieu dans SQL Server, donc chaque ligne est renvoyée.

Si j'y vais:

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

Ensuite, il s'exécute rapidement, probablement parce que la condition est transmise à Oracle pour que l'index Oracle de la table soit utilisé.

Mon problème est que je veux créer une vue. Je ne trouve pas de moyen d'utiliser la deuxième version du code pour créer une vue. Si je fais simplement:

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

Ensuite, ça coule lentement.

Existe-t-il un autre format pour le littéral de date que SQL Server transmettra à Oracle ou existe-t-il une autre solution? Je me demandais aussi s’il s’agissait des paramètres utilisés pour créer le lien avec Oracle. Pour référence, ils sont:

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

EDIT: Je viens de trouver une question très similaire: Forcer une requête SQL Remote à filtrer à distance plutôt que localement

7
Richard A

Je préfère le format 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

La date simple n'est pas indépendante de la culture ...

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

Mais cela fonctionne - cependant - avec le type de cible DATE (cette différence est plutôt étrange ...):

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

Thx to lad2025 je veux ajouter pour compléter le "complet" ISO 8601, qui fonctionne très bien:

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
11
Shnugo

Je recommanderais d'utiliser le format complet ISO 8601 proposé par @ lad2025:

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

Ceci est supérieur au format ODBC suggéré par @Shnugo.

Dans SQL Server 2014 au moins, le format ODBC ne fonctionnera pas pour les dates antérieures à 1753-01-01 (par exemple, les dates en dehors de la plage de l'ancien type de données DATETIME), alors que le format ISO 8601 .

Pour tester cela vous-même, essayez les requêtes suivantes:

--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;

Même si vous pensez que les dates avec lesquelles vous travaillez ne seront jamais avant l'an 1753, c'est une bonne habitude. Je me suis heurté à cette difficulté tout en cherchant à mettre en place un tableau de calendrier à référencer dans les requêtes.

3
Tidorith

Je suggère d'utiliser le littéral de date ANSI date qui utilise un format fixe AAAA-MM-JJ.

Par exemple,

DATE '2015-10-20'

Dans Oracle, '20140701' est un chaîne et non un DATE. Vous pourriez avoir de la chance de voir un conversion implicite de type de données et obtenir le résultat en fonction du paramètres NLS spécifiques à la localisation de votre client. Vous devriez toujours l'éviter et explicitement convertir la chaîne en date pour les comparaisons de date.

3
Lalit Kumar B