it-swarm.com.de

SQL-Abfrage, um N Zeilen von dual zurückzugeben

Ich möchte eine SQL-Abfrage schreiben, die eine Bindevariable (z. B. NUM) akzeptiert und deren Ausgabe aus einer Spalte und NUM Zeilenanzahl besteht, wobei jede Zeile ihre Zeilennummer hat. d.h. wenn wir übergeben: NUM als 7, sollte die Ausgabe sein:

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

Die Abfrage sollte keine tatsächlichen DB-Tabellen enthalten, und es sollte kein PL/SQL-Code verwendet werden. in der Abfrage sollte nur dual verwendet werden

Gibt es eine Möglichkeit, dies zu erreichen?

14
Harish

Du könntest benutzen:

 WHERE ROWNUM <= :NUM

... aber die Tabelle muss eine Zeile enthalten, die gleich oder größer als das Limit in der Bindevariablen ist. Dieser Link demonstriert verschiedene Zeilennummerngenerierungstechniken in Oracle .

Mit CONNECT BY, Oracle 10g +:

SELECT LEVEL
  FROM DUAL
CONNECT BY LEVEL <= :NUM

Bestätigt durch monojohnny, dass die Bindevariable verwendet werden kann. Versuche, unter Oracle 9i ausgeführt zu werden, obwohl die CONNECT BY -Syntax unterstützt wird, führen zu einem ORA-01436-Fehler.

Das Einzige, worauf ich nicht 100% bin, ist, dass CONNECT BY das Limit der Bind-Variablen akzeptiert.

Referenz:

34
OMG Ponies

Versuchen Sie etwas wie:

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;

Es ist chaotisch, aber es wird den Trick machen.

Bearbeitet: Ah - Sie müssen eine Variable übergeben, um zu wissen, wie hoch Sie gehen müssen ...

Wie wäre es also mit so etwas wie:

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;

Ok ... nochmal editieren, jetzt mit 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

Ich habe mir diese Antwort nicht ausgedacht [also stellen Sie sicher, dass alle Abstimmungen in die richtige Richtung gehen !!], sondern nur meine Testnotizen basierend auf 'OMG Ponies' [wer war sich nicht sicher, ob die Methode mit Bindungsvariablen funktionieren würde] oben als Referenz:

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

Abfrage ohne Verbindung durch

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

Ich markiere dieses Community-Wiki, da es Ihrer Anforderung nach keinen Tabellen entspricht. Bei der Installation einer Datenbank müssen Sie jedoch zunächst eine Reihe von Tabellen für diesen Zweck erstellen.

  • Eine Tabelle mit einer großen Anzahl von ganzen Zahlen (z. B. -99999 bis 99999).
  • Eine Tabelle, die jedes Datum von 10 Jahren in der Vergangenheit bis zu 10 Jahren in der Zukunft enthält (die kontinuierlich zu jedem Monat hinzugefügt und gelegentlich angepasst wird).
  • Eine Tabelle, die jede Stunde des Tages enthält.

Auf diese Weise reduzieren wir die Komplexität und erhöhen die Geschwindigkeit einer großen Anzahl unserer Abfragen auf Kosten des (minimalen und billigen) Speicherplatzes.

Sie sollten ernsthaft darüber nachdenken. Abgesehen von der Pflege der Datumstabelle ist nicht viel Unterhalt erforderlich.

0
paxdiablo

Eine andere Möglichkeit ist die Verwendung eines XQuery-Bereichsausdrucks, z.

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10

Diese Lösung ist sehr flexibel, z.

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

Eine andere Lösung würde erfordern, dass PL/SQL eine Funktion erstellt, um eine Auflistung mit den Zeilen zurückzugeben ... Nicht so einfach wie der select level from dual connect by level <= :b1-Ansatz, aber in einigen Situationen nützlich:

1) Erstellen Sie einen Nummerntabellen-Objekttyp (in diesem Beispiel number_tbl):

create or replace type number_tbl as table of number;

2) Erstellen Sie eine Funktion, die die Anzahl der zu generierenden Zeilen erhält, und geben Sie dann ein number_tbl-Objekt mit den folgenden Ergebnissen zurück:

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) Wählen Sie mit der Funktion table( ... ) aus Ihrer Funktion aus, um Ihr number_tbl-Objekt in etwas Auswählbares zu verwandeln:

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;

Zurückgegebene Zeilen 0 1 2 3 4 5 6 7 8 9 10

connect by ist so eine wundervolle Sache. Es hilft Ihnen, mehrere Zeilen mit einem einzigen Datensatz zu generieren, der in einer Doppeltabelle verfügbar ist. Dies kann Ihnen helfen, eine große Anzahl von Zeilen für Ihre Dummy-Daten zu generieren. Zum Beispiel

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

oder Sie können so etwas tun

Beispiel 2: Sie möchten Quadrate und Würfel mit Zahlen von 1 bis 10 drucken.

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

Daher können Sie es in jeder gewünschten Form manipulieren. Auf diese Weise können Sie mehrere Zeilen aus einer Doppeltabelle zurückgeben. Referenzen: http://www.oraclebin.com/2012/12/multipe-rows-from-dual-table.html

0
Sushant Butta