Bei zwei Zahlen n
und m
möchte ich eine Reihe des Formulars generieren
1, 2, ..., (n-1), n, n, (n-1), ... 2, 1
und wiederhole es m
mal.
Zum Beispiel möchte ich für n = 3
und m = 4
eine Folge der folgenden 24 Zahlen:
1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1, 1, 2, 3, 3, 2, 1
---------------- ---------------- ---------------- ----------------
Ich weiß, wie dieses Ergebnis in PostgreSQL mit einer von zwei Methoden erzielt werden kann:
Verwenden Sie die folgende Abfrage, die die generate_series
Funktion verwendet, und einige Tricks, um sicherzustellen, dass die Reihenfolge die richtige ist:
WITH parameters (n, m) AS
(
VALUES (3, 5)
)
SELECT
xi
FROM
(
SELECT
i, i AS xi
FROM
parameters, generate_series(1, parameters.n) AS x(i)
UNION ALL
SELECT
i + parameters.n, parameters.n + 1 - i AS xi
FROM
parameters, generate_series(1, parameters.n) AS x(i)
) AS s0
CROSS JOIN
generate_series (1, (SELECT m FROM parameters)) AS x(j)
ORDER BY
j, i ;
... oder verwenden Sie eine Funktion für denselben Zweck mit angrenzenden und verschachtelten Schleifen:
CREATE FUNCTION generate_up_down_series(
_elements /* n */ integer,
_repetitions /* m */ integer)
RETURNS SETOF integer AS
$BODY$
declare
j INTEGER ;
i INTEGER ;
begin
for j in 1 .. _repetitions loop
for i in 1 .. _elements loop
return next i ;
end loop ;
for i in reverse _elements .. 1 loop
return next i ;
end loop ;
end loop ;
end ;
$BODY$
LANGUAGE plpgsql IMMUTABLE STRICT ;
Wie könnte ich das Äquivalent entweder in Standard-SQL oder in Transact-SQL / SQL Server tun?
quelle
Postgres
Sie können es mit einer einzigen
generate_series()
und grundlegenden Mathematik arbeiten lassen (siehe mathematische Funktionen ).Eingewickelt in eine einfache SQL-Funktion:
Anruf:
Erzeugt das gewünschte Ergebnis. n und m können eine beliebige Ganzzahl sein, bei der n * 2 * m nicht überläuft
int4
.Wie?
In der Unterabfrage:
Generieren Sie die gewünschte Gesamtzahl der Zeilen ( n * 2 * m ) mit einer einfachen aufsteigenden Anzahl. Ich nenne es
n2m
. 0 bis N-1 (nicht 1 bis N ), um das folgende Modulo zu vereinfachen Operation .Nehmen Sie % n * 2 (
%
ist der Modulo-Operator), um eine Reihe von n aufsteigenden Zahlen m- mal zu erhalten. Ich nenne esn2
.In der äußeren Abfrage:
Addiere 1 zur unteren Hälfte ( n2 <n ).
Für die obere Hälfte ( n2> = n ) Spiegel der unteren Hälfte mit n * 2 - n2 .
Ich habe hinzugefügt
ORDER BY
, um die angeforderte Bestellung zu garantieren. Mit aktuellen Versionen oder Postgres funktioniert es auch ohneORDER BY
die einfache Abfrage - aber nicht unbedingt bei komplexeren Abfragen! Dies ist ein Implementierungsdetail (und es wird sich nicht ändern), das jedoch vom SQL-Standard nicht garantiert wird.Leider
generate_series()
ist Postgres spezifisch und nicht Standard-SQL, wie kommentiert wurde. Aber wir können dieselbe Logik wiederverwenden:Standard SQL
Sie können die Seriennummern mit einem rekursiven CTE anstelle von
generate_series()
oder effizienter für die wiederholte Verwendung generieren und einmal eine Tabelle mit Serien-Ganzzahlen erstellen. Jeder kann lesen, niemand kann darauf schreiben!Dann wird das Obige
SELECT
noch einfacher:quelle
Wenn Sie einfaches SQL benötigen. Theoretisch sollte es auf den meisten DBMS funktionieren (getestet auf PostgreSQL und SQLite):
Erläuterung
Generieren Sie die Serie 1..n
Vorausgesetzt, dass
n=3
Es ist recht einfach und kann in fast allen Dokumenten über rekursive CTEs gefunden werden. Wir benötigen jedoch zwei Instanzen von jedem Wert
Generieren Sie die Serien 1,1, .., n, n
Hier verdoppeln wir nur den Anfangswert, der zwei Zeilen hat, aber den zweiten Haufen, den wir brauchen, in umgekehrter Reihenfolge, also werden wir die Reihenfolge in Kürze einführen.
Bevor wir die Reihenfolge einführen, beachten Sie, dass dies auch eine Sache ist. Wir können zwei Zeilen in der Startbedingung mit jeweils drei Spalten haben, unsere
n<3
ist immer noch eine einzelne Spaltenbedingung. Und wir steigern immer noch nur den Wert vonn
.Ebenso können wir sie ein wenig verwechseln, beobachten, wie sich unsere Startbedingungen hier ändern : hier haben wir eine
(6,2)
,(1,1)
Generieren Sie die Serien 1..n, n..1
Der Trick hier besteht darin, die Serie (1..n) zweimal zu generieren und dann einfach die Reihenfolge im zweiten Satz zu ändern.
Hier
i
ist die Reihenfolge undz
die Nummer der Sequenz (oder die Hälfte der Sequenz, wenn Sie möchten). Für Sequenz 1 erhöhen wir also die Reihenfolge von 1 auf 3 und für Sequenz 2 verringern wir die Reihenfolge von 6 auf 4. Und schließlichMultiplizieren Sie die Reihe mit
m
(siehe die erste Abfrage in der Antwort)
quelle
Wenn Sie eine tragbare Lösung wünschen, müssen Sie erkennen, dass dies im Grunde ein mathematisches Problem ist.
Wenn @n als höchste Nummer der Sequenz und @x als Position der Nummer in dieser Sequenz angegeben wird (beginnend mit Null), würde die folgende Funktion in SQL Server funktionieren:
Sie können dies mit diesem CTE überprüfen:
(Kurze Erklärung: Die Funktion verwendet MODULO (), um eine Folge sich wiederholender Zahlen zu erstellen, und ABS (), um daraus eine Zick-Zack-Welle zu machen. Die anderen Operationen transformieren diese Welle so, dass sie dem gewünschten Ergebnis entspricht.)
quelle
In PostgreSQL ist dies einfach,
quelle
Dies funktioniert in MS-SQL und ich denke, kann für jede SQL-Variante geändert werden.
quelle
Eine Möglichkeit, dies in SQL Server mithilfe eines rekursiven cte zu tun.
1) Generieren Sie die erforderliche Anzahl von Mitgliedern in der Reihe (für n = 3 und m = 4 wäre es 24, was 2 * n * m ist)
2) Anschließend können Sie mithilfe der Logik in einem
case
Ausdruck die erforderlichen Reihen generieren.Sample Demo
Wie von @AndriyM vorgeschlagen .. kann der
case
Ausdruck vereinfacht werdenDemo
quelle
Verwenden Sie nur grundlegende Mathematik
+ - * /
und Modulo:Dies erfordert kein bestimmtes SGBD.
Mit
numbers
einer Zahlentabelle:Dadurch wird eine Zahlentabelle (1-1000) ohne Verwendung eines rekursiven CTE generiert. Siehe Beispiel . 2 * n * m muss kleiner sein als die Anzahl der Zeilen in Zahlen.
Ausgabe mit n = 3 und m = 4:
Diese Version erfordert eine kleinere Zahlentabelle (v> = n und v> = m):
Siehe Beispiel .
quelle
Eine Grundfunktion mit Iteratoren.
T-SQL
Postgres
quelle
quelle