2016-11-02 14 views
0

Given;OracleのNTH行のクエリが予期したとおりに動作しない

CREATE TABLE T1 (ID INTEGER, DESCRIPTION VARCHAR2(20)); 
INSERT INTO T1 VALUES (1,'ONE'); 
INSERT INTO T1 VALUES (2,'TWO'); 
INSERT INTO T1 VALUES (3,'THREE'); 
INSERT INTO T1 VALUES (4,'FOUR'); 
INSERT INTO T1 VALUES (5,'FIVE'); 
COMMIT; 

なぜですか。

SELECT * FROM 
(SELECT ROWNUM, ID, DESCRIPTION 
    FROM T1) 
WHERE MOD(ROWNUM,1)=0; 

戻り

ROWNUM          ID DESCRIPTION   
------ -------------------------------------- -------------------- 
    1          1 ONE     
    2          2 TWO     
    3          3 THREE     
    4          4 FOUR     
    5          5 FIVE 

のに対し、

SELECT * FROM 
(SELECT ROWNUM, ID, DESCRIPTION 
    FROM T1) 
WHERE MOD(ROWNUM,2)=0; 

ゼロの行を返しますか?

混乱は、ROWNUM =(2,4)が返されることが期待...

+0

別名ROWNUMおよび FROM句が動作するはず... – xQbert

+0

SELECT *にエイリアスを参照 MOD(t.rn 2 Tと(RN、ID、T1 FROM DESCRIPTION としてROWNUMを選択) )= 0; –

+0

'ROWNUM'は、行が' WHERE'節によってフィルタリングされた後に割り当てられます。したがって、 'ROWNUM' 1を削除するフィルタは、行が返されないようにします。同様に、「ROWNUM」2をフィルタリングする任意のクエリは、ロー1が返されることを防ぐ。 'WHERE MOD(ROWNUM、5)<= 3'は、テーブルにいくつの行が存在するかにかかわらず最初の3行だけを返し、' WHERE ROWNUM <= 3'述語に相当します。 – Sentinel

答えて

1
SELECT B.* FROM 
(SELECT ROWNUM a, ID, DESCRIPTION 
    FROM T1) B 
WHERE MOD(A,2)=0; 

理由:あなたのアプローチは、二回ROWNUMを実行する必要があります。あなたはする必要はありません。あなたは本当にやりたいことはありません。操作の順序に基づいて、where句は外側の選択の前に実行されます。これは、selectが各行の値を決定しておらず、行数が未知であることを意味します。

追加:

私はrownumbersエンジンが派生するものとは対照的に、期待される特定の順序であるように、インライン・ビューに順を追加することをお勧めします。

+0

??それは一体何の意味ですか?行番号は、行の作成時に割り当てられます。取り込まれた最初の行はrownum = 1に割り当てられ、rownumはNULLではありません。それは単にWHERE句に失敗します。次に、取り込まれた次の行にrownum = 1が割り当てられ、再びWHEREに失敗し、実際に行が選択されなくなるまで続きます。あなたの説明では、ROWNUM <= 10はどこでも失敗するはずです。そうでない場合は、自分で試してみてください。 – mathguy

+0

@mathguyそれが真であれば<> 0を使うとすべての行を正しく取得する必要があるでしょうか?どちらの場合もそうではありません。だから何かが続いている。これは、エンジンが1行だけ先を見ているようなもので、where句を評価するときに使用します。 (2つのUNCH SELECT 'B'をデュアルから UNON SELECT 'C'をデュアルから UNON SELECT 'D'をダブルクリックして選択してください) ここで、mod(rownum、2)は、 <> 0'は4行を返す必要があります。 (奇妙なことに、コメントに正しい組合のスペルを含めることができませんでした) – xQbert

+0

'<>'をどこで使うのですか? 'mod(rownum、2)'では?いいえ - その場合、最初の行が通過し、次に2番目の行が失敗し、次の行が「2番目」になり、失敗し、次の行が失敗します。したがって、 'mod(rownum、2)<> '0では、クエリによって最初に検索された行が1行だけ取得されます。 – mathguy

1

あなたはの操作ROWNUMを持っています。
1番目のROWNUMは1から5までの数字を生成します。
ROWNUMの値が1で、MOD(1,2)=0がfalseであるため、2番目のROWNUMは何も生成しません。レコードは出力されず、ROWNUMは存在しません増分され、何度も何度も失敗します。エイリアスを使用して


このクエリで、あなたが期待している正確に何を返します。

SELECT * FROM 
(SELECT ROWNUM as rn, ID, DESCRIPTION 
    FROM T1) 
WHERE MOD(rn,2)=0; 
0

OracleでROWNUM疑似列に関するいくつかの事実:

  • 各行に割り当てられたROWNUMがありますOracleがDBから行を取得する順序によって決定されます。
  • 戻される順序は決まっていません。一度実行すると、1つの順序で行が戻され、2回目は、基本表が再編成された場合や、別の問合せ計画。
  • ROWNUMが行に割り当てられる順序は、order by句の順序と必ずしも相関していません(order by句は、異なるクエリプランを使用する可能性があるため、ROWNUMの順序に影響する可能性があります)。ROWNUM bersはソート順と一致しない可能性があります)。
  • ROWNUMレコードはWHERE句でフィルタリングされた後に割り当てられます。したがって、ROWNUMをフィルタリングすると、決してレコードが返されません。
  • 外部クエリが行をフィルタリングする前にサブクエリ全体が外部クエリに返されるが、ROWNUMは依然として非決定的な順序を持つため、エイリアス化されたROWNUM列を返すサブクエリのフィルタリングは機能します。

決定的な方法で上位NまたはN行目のクエリを正常に返すには、決定的な方法で行番号を割り当てる必要があります。 ROW_NUMBER

select * from 
(select ROW_NUMBER() over (order by ID) rn 
     , ID 
     , DESCRIPTION 
    from T1) 
where rn <= 4 -- Top N 

又は

where rn = 4 -- 1st Nth row 

又はいずれの場合にも

WHERE MOD(rn,2)=0 -- every Nth row 

ORDER BY句:そのような方法は、サブクエリで `ROW_NUMBER」分析関数を使用することです解析関数はデータの細かさと一致する必要があります。そうでない場合は、順序付けの結びつきは再び非決定論的であり、現在のものと一致する可能性が最も高いROWNUM発注。内側選択で

関連する問題