web-dev-qa-db-ja.com

デュアルからN行を返すSQLクエリ

バインド変数(たとえば:NUM)を受け入れるSQLクエリを作成し、その出力は1つの列と:NUMの行数で構成され、各行には行番号があります。つまり、:NUMを7として渡すと、出力は次のようになります。

VAL
====
1
2
3
4
5
6
7

クエリに実際のDBテーブルを含めたり、PL/SQLコードを使用したりしないでください。つまり、クエリではデュアルのみを使用する必要があります

これを達成する方法はありますか?

14
Harish

あなたが使用することができます:

 WHERE ROWNUM <= :NUM

...ただし、テーブルには、バインド変数の制限以上の行が含まれている必要があります。 このリンクは、Oracleでのさまざまな行番号生成手法を示しています

CONNECT BYを使用して、Oracle 10g +:

SELECT LEVEL
  FROM DUAL
CONNECT BY LEVEL <= :NUM

バインド変数を使用できることをmonojohnnyで確認しました。 CONNECT BY構文はサポートされていますが、Oracle 9iで実行しようとすると、ORA-01436エラーが発生します。

私が100%ではない唯一のことは、CONNECTBYがバインド変数からの制限を受け入れるかどうかです。

参照:

34
OMG Ponies

次のようなものを試してください:

SELECT 1 AS Val FROM dual
UNION ALL SELECT 2 FROM dual
UNION ALL SELECT 3 FROM dual
UNION ALL SELECT 4 FROM dual
UNION ALL SELECT 5 FROM dual
UNION ALL SELECT 6 FROM dual
UNION ALL SELECT 7 FROM dual;

それは厄介ですが、それはトリックを行います。

編集:ああ-どのくらいの高さになるかを知らせるために変数を渡す必要があります...

では、次のようなものはどうですか?

SELECT t1.Val + t2.Val * 2 + t3.Val * 4 + t4.Val * 8 AS Val
FROM
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t1, 
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t2, 
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t3, 
(
SELECT 0 AS Val FROM dual
UNION ALL SELECT 1 FROM dual
) AS t4
WHERE t1.Val + t2.Val * 2 + t3.Val * 4 + t4.Val * 8 <= 7;

わかりました...もう一度編集します。WITHを使用します。

WiTH 
A0 AS (SELECT 0 as N FROM DUAL UNION ALL SELECT 0 FROM DUAL),
A1 AS (SELECT 0 as N FROM A0, A0 AS B),
A2 AS (SELECT 0 as N FROM A1, A1 AS B),
A3 AS (SELECT 0 as N FROM A2, A2 AS B),
A4 AS (SELECT 0 as N FROM A3, A3 AS B),
A5 AS (SELECT 0 as N FROM A4, A4 AS B),
A6 AS (SELECT 0 as N FROM A5, A5 AS B),
Nums AS (SELECT ROW_NUMBER() OVER (ORDER BY N) AS Val FROM A6)
SELECT *
FROM Nums
WHERE Val <= :NUM
;
4
Rob Farley

私はこの答えを思いつきませんでした[投票が正しい方向に進むことを確認してください!!]、それは上記の「OMGPonies」[メソッドがバインディング変数で機能するかどうかわからなかった]に基づく私のテストノートです参考のために:

Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> var num_rows number
SQL> begin select 20 into :num_rows from dual;
  2  end;
  3  /

PL/SQL procedure successfully completed.

SQL> select level from dual
  2  connect by level <=:num_rows;

     LEVEL
----------
         1
         2
         3
         4
 ...
3
monojohnny

接続せずにクエリ

WITH num(n) as(select 1 from dual union all
select n+1 from num where n <= :num_limit)
select * from num
2
lunicon

このコミュニティウィキは、テーブルがないという要件に実際には答えていないため、マークを付けていますが、データベースをインストールするときに最初に行うことの1つは、この種の目的でテーブルのセットを作成することです。

  • 多数の整数を含むテーブル(例:-99999から99999)。
  • 過去10年から将来10年までのすべての日付を含むテーブル(毎月継続的に追加され、ときどきトリミングされます)。
  • 1日の各時間を含むテーブル。

これを行うことにより、(最小限で安価な)ディスク容量を犠牲にして、多数のクエリの複雑さを大幅に軽減し、速度を向上させます。

あなたはそれについて真剣に考えるべきです。日付テーブルを維持することを除けば、必要な維持管理はそれほど多くありません。

0
paxdiablo

別の方法は、XQuery範囲式を使用することです。例:

select column_value from xmltable(:a||' to '||:b);

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

このソリューションは非常に柔軟性があります。例:

select column_value from xmltable('5 to 10, 15 to 20');

 5
 6
 7
 8
 9
10
15
16
17
18
19
20
0
Jeffrey Kemp

別の解決策では、行を含むコレクションを返す関数を作成するためにPL/SQLが必要になります..._select level from dual connect by level <= :b1_アプローチほど単純ではありませんが、いくつかの状況で役立ちます。

1)数値テーブルオブジェクトタイプ(この例ではnumber_tbl)を作成します。

_create or replace type number_tbl as table of number;
_

2)生成される行数を受け取る関数を作成し、結果とともにnumber_tblオブジェクトを返します。

_create or replace function get_rows( i_num_rows number ) return number_tbl as
  t number_tbl := number_tbl();
begin
  if i_num_rows < 1 then
    return null;
  end if;

  t.extend( i_num_rows );

  for i in 1..i_num_rows loop
    t(i) := i;
  end loop;

  return t;
end get_rows;
_

3)table( ... )関数を使用して関数から選択し、number_tblオブジェクトを選択可能なものに変換します。

_select * from table( cast ( get_rows( :b1 ) as number_tbl ) );
_
0
R. Genaro
WITH cte_numbers(n) 
AS (
    SELECT 0
    UNION  ALL
    SELECT n + 1
    FROM  cte_numbers
    WHERE n < 10
)
SELECT n
FROM cte_numbers;

返された行01 2 3 4 5 6 7 8 9 10

接続するのはとても素晴らしいことです。デュアルテーブルで利用可能な単一のデータセットで複数の行を生成するのに役立ちます。これは、ダミーデータの膨大な数の行を生成するのに役立ちます。例えば

insert into test select a.* from test1 a,(select * from dual connect by level <=100000) b;

またはあなたはこのようなことをすることができます

例2:1から10までの数の平方と立方体を印刷したいとします。

SQL> select level "No", power(level,2) "Square", power(level,3) "Cube"  from dual     connect by level <= 10;

    No     Square       Cube
---------- ---------- ----------
     1          1          1
     2          4          8
     3          9         27
     4         16         64
     5         25        125
     6         36        216
     7         49        343
     8         64        512
     9         81        729
    10        100       1000

したがって、好きな形で操作できます。これは、デュアルテーブルから複数の行を返す方法です。参照: http://www.oraclebin.com/2012/12/multipe-rows-from-dual-table.html

0
Sushant Butta