J'ai de la difficulté à convertir les procédures stockées de SQL Server en Oracle pour que notre produit soit compatible avec celui-ci.
J'ai des requêtes qui renvoient l'enregistrement le plus récent de certaines tables, basé sur un horodatage:
SQL Server:
SELECT TOP 1 *
FROM RACEWAY_INPUT_LABO
ORDER BY t_stamp DESC
=> Cela me rendra le dernier enregistrement
Mais Oracle:
SELECT *
FROM raceway_input_labo
WHERE rownum <= 1
ORDER BY t_stamp DESC
=> Cela me retournera l'enregistrement le plus ancien (probablement en fonction de l'index), quelle que soit l'instruction ORDER BY
!
J'ai encapsulé la requête Oracle de cette manière pour répondre à mes exigences:
SELECT *
FROM
(SELECT *
FROM raceway_input_labo
ORDER BY t_stamp DESC)
WHERE rownum <= 1
et il fonctionne. Mais cela me semble être un horrible bidouillage, surtout si j’ai beaucoup de disques dans les tables concernées.
Quel est le meilleur moyen d'y parvenir?
L'instruction where
est exécutée avant le order by
. Ainsi, votre requête souhaitée dit "prenez la première ligne puis commandez-la part_stamp
desc". Et ce n'est pas ce que vous avez l'intention.
La méthode de sous-requête est la méthode appropriée pour le faire dans Oracle.
Si vous voulez une version qui fonctionne sur les deux serveurs, vous pouvez utiliser:
select ril.*
from (select ril.*, row_number() over (order by t_stamp desc) as seqnum
from raceway_input_labo ril
) ril
where seqnum = 1
Le *
extérieur renverra "1" dans la dernière colonne. Pour éviter cela, vous devez répertorier les colonnes individuellement.
Utilisez ROW_NUMBER()
à la place. ROWNUM
est une pseudo-colonne et ROW_NUMBER()
est une fonction. Vous pouvez lire la différence entre eux et voir la différence dans le résultat des requêtes ci-dessous:
SELECT * FROM (SELECT rownum, deptno, ename
FROM scott.emp
ORDER BY deptno
)
WHERE rownum <= 3
/
ROWNUM DEPTNO ENAME
---------------------------
7 10 CLARK
14 10 MILLER
9 10 KING
SELECT * FROM
(
SELECT deptno, ename
, ROW_NUMBER() OVER (ORDER BY deptno) rno
FROM scott.emp
ORDER BY deptno
)
WHERE rno <= 3
/
DEPTNO ENAME RNO
-------------------------
10 CLARK 1
10 MILLER 2
10 KING 3
Une autre solution que je suggérerais dans ce cas d'utilisation consiste à utiliser MAX (t_stamp) pour obtenir la dernière ligne ... par exemple.
select t.* from raceway_input_labo t
where t.t_stamp = (select max(t_stamp) from raceway_input_labo)
limit 1
Ma préférence de modèle de codage (peut-être) - fiable, fonctionne généralement mieux ou mieux que d'essayer de sélectionner la 1ère ligne dans une liste triée - l'intention est également plus explicitement lisible.
J'espère que cela t'aides ...
SQLer
Documenté quelques problèmes de conception avec cela dans un commentaire ci-dessus. Bref récit, sous Oracle, vous devez limiter les résultats manuellement lorsque vous disposez de tables volumineuses et/ou de tables portant le même nom de colonne (et que vous ne souhaitez pas les taper explicitement et les renommer tous). La solution facile consiste à déterminer votre point d'arrêt et à le limiter dans votre requête. Vous pouvez également le faire dans la requête interne si la contrainte de noms de colonnes en conflit n’est pas présente. Par exemple.
WHERE m_api_log.created_date BETWEEN TO_DATE('10/23/2015 05:00', 'MM/DD/YYYY HH24:MI')
AND TO_DATE('10/30/2015 23:59', 'MM/DD/YYYY HH24:MI')
va réduire considérablement les résultats. Ensuite, vous pouvez ORDER BY ou même faire la requête externe pour limiter les lignes.
En outre, je pense que TOAD a une fonctionnalité pour limiter les lignes; mais, pas sûr que cela limite dans la requête sur Oracle. Pas certain.