...nur einige Artikel aus einer Warengruppe finden

edewolf

Benutzer
Beiträge
13
Einen schönen Guten Tag,
Ich habe Artikel unterteilt in Hauptwarengruppe und Unterwarengruppe
Ich hätte gern ein query mit folgendem Ergebnis:
Liste einer bestimmten Hauptwarengruppe (H1) mit allen Unterwarengruppen (U1) aber immer nur 5 (limit 5) Artikel aus der Unterwarengruppe.
Ist das mit einem Query möglich?
Danke für die Hilfe
Liebe Grüße
Ede
 
Werbung:
hrm, dauert mir zu lange...

Code:
test=# create table edewolf(h1 int, u1 int, name text);
CREATE TABLE
test=*# insert into edewolf select h, u, 'Produkt ' || h::text || ' ' || u::text from generate_Series(1,5) h cross join generate_Series(1,10) u;
INSERT 0 50
test=*# select * from edewolf ;
 h1 | u1 |     name     
----+----+--------------
  1 |  1 | Produkt 1 1
  1 |  2 | Produkt 1 2
  1 |  3 | Produkt 1 3
  1 |  4 | Produkt 1 4
  1 |  5 | Produkt 1 5
  1 |  6 | Produkt 1 6
  1 |  7 | Produkt 1 7
  1 |  8 | Produkt 1 8
  1 |  9 | Produkt 1 9
  1 | 10 | Produkt 1 10
  2 |  1 | Produkt 2 1
  2 |  2 | Produkt 2 2
  2 |  3 | Produkt 2 3
  2 |  4 | Produkt 2 4
  2 |  5 | Produkt 2 5
  2 |  6 | Produkt 2 6
  2 |  7 | Produkt 2 7
  2 |  8 | Produkt 2 8
  2 |  9 | Produkt 2 9
  2 | 10 | Produkt 2 10
  3 |  1 | Produkt 3 1
  3 |  2 | Produkt 3 2
  3 |  3 | Produkt 3 3
  3 |  4 | Produkt 3 4
  3 |  5 | Produkt 3 5
  3 |  6 | Produkt 3 6
  3 |  7 | Produkt 3 7
  3 |  8 | Produkt 3 8
  3 |  9 | Produkt 3 9
  3 | 10 | Produkt 3 10
  4 |  1 | Produkt 4 1
  4 |  2 | Produkt 4 2
  4 |  3 | Produkt 4 3
  4 |  4 | Produkt 4 4
  4 |  5 | Produkt 4 5
  4 |  6 | Produkt 4 6
  4 |  7 | Produkt 4 7
  4 |  8 | Produkt 4 8
  4 |  9 | Produkt 4 9
  4 | 10 | Produkt 4 10
  5 |  1 | Produkt 5 1
  5 |  2 | Produkt 5 2
  5 |  3 | Produkt 5 3
  5 |  4 | Produkt 5 4
  5 |  5 | Produkt 5 5
  5 |  6 | Produkt 5 6
  5 |  7 | Produkt 5 7
  5 |  8 | Produkt 5 8
  5 |  9 | Produkt 5 9
  5 | 10 | Produkt 5 10
(50 rows)
test=*# select e1.h1, e2.u1, e2.name from (select distinct h1 from edewolf) e1 left join lateral (select * from edewolf e2 where h1 = e1.h1 order by e2.u1 limit 5) e2 on true order by h1, u1;
 h1 | u1 |    name     
----+----+-------------
  1 |  1 | Produkt 1 1
  1 |  2 | Produkt 1 2
  1 |  3 | Produkt 1 3
  1 |  4 | Produkt 1 4
  1 |  5 | Produkt 1 5
  2 |  1 | Produkt 2 1
  2 |  2 | Produkt 2 2
  2 |  3 | Produkt 2 3
  2 |  4 | Produkt 2 4
  2 |  5 | Produkt 2 5
  3 |  1 | Produkt 3 1
  3 |  2 | Produkt 3 2
  3 |  3 | Produkt 3 3
  3 |  4 | Produkt 3 4
  3 |  5 | Produkt 3 5
  4 |  1 | Produkt 4 1
  4 |  2 | Produkt 4 2
  4 |  3 | Produkt 4 3
  4 |  4 | Produkt 4 4
  4 |  5 | Produkt 4 5
  5 |  1 | Produkt 5 1
  5 |  2 | Produkt 5 2
  5 |  3 | Produkt 5 3
  5 |  4 | Produkt 5 4
  5 |  5 | Produkt 5 5
(25 rows)

Das wäre ine Lösung via LATERAL JOIN. Und hier eine via Window-Funktions:

Code:
test=*# with foo as (select *, row_number() over(partition by h1 order by u1) from edewolf) select * from foo where row_number <= 5 ;
 h1 | u1 |    name     | row_number
----+----+-------------+------------
  1 |  1 | Produkt 1 1 |          1
  1 |  2 | Produkt 1 2 |          2
  1 |  3 | Produkt 1 3 |          3
  1 |  4 | Produkt 1 4 |          4
  1 |  5 | Produkt 1 5 |          5
  2 |  1 | Produkt 2 1 |          1
  2 |  2 | Produkt 2 2 |          2
  2 |  3 | Produkt 2 3 |          3
  2 |  4 | Produkt 2 4 |          4
  2 |  5 | Produkt 2 5 |          5
  3 |  1 | Produkt 3 1 |          1
  3 |  2 | Produkt 3 2 |          2
  3 |  3 | Produkt 3 3 |          3
  3 |  4 | Produkt 3 4 |          4
  3 |  5 | Produkt 3 5 |          5
  4 |  1 | Produkt 4 1 |          1
  4 |  2 | Produkt 4 2 |          2
  4 |  3 | Produkt 4 3 |          3
  4 |  4 | Produkt 4 4 |          4
  4 |  5 | Produkt 4 5 |          5
  5 |  1 | Produkt 5 1 |          1
  5 |  2 | Produkt 5 2 |          2
  5 |  3 | Produkt 5 3 |          3
  5 |  4 | Produkt 5 4 |          4
  5 |  5 | Produkt 5 5 |          5
(25 rows)

test=*#

Die erstere Lösung ist effizienter, bei der zweiten Lösung wird das Subselect erst einmal komplett materialisiert.
 
Vielen Dank für die schnelle Antwort

Ich habe jedoch einen sql Fehler(1064) near

(select * from edewolf e2 where h1 = e1.h1 order by e2.u1 limit 5) e2
on true order by h1, u1

lg
ede
 
dürfte daran liegen, daß LATERAL JOINS zum großen Set von Features gehört, die MySQL schlicht nicht kann, nicht einmal parsen. Check Constraints sind da z.B. schon besser: die 'versteht' MySQL, ignoriert sie aber.
 
ich habe noch eine andere Lösung gezeigt, mit Window-Function row_number(). Ist nur nicht so effizient. Mit MySQL hast halt ein Relikt aus den Anfängen, was nicht viel kann.
Wie wäre der Einsatz einer modernen Datenbank?
 
... kann man lateral join ev durch ein subquerie ersetzen?

Nein, um das kurz zu erklären. Eine Subquery wird nur EINMAL ausgeführt, ein LATERAL JOIN wird aber für jede Zeile der einen Tabelle ausgefüht, als quasi als korrelierte Subquery. Das macht LATERAL JOINs so besonders. Für jede Row der der einen Tabelle wird die Subquery ausgeführt, innerhalb dieser kann ich auf Werte der aktuellen Zeile der 'treibenden' Tabelle zugreifen. Daher entfällt auch die JOIN-CONDITION, die ist ein ON TRUE gesetzt.

Wenn Du also je Obergruppe sehr viele Untergruppen hast und darauf einen Index und in der Abfrage ein ORDER BY mit LIMIT, dann zieht das nur die via LIMIT benötigte Anzahl via Index. Bei der Lösung mit row_number() nummerierst Du erst mal ALLE records. Angenommen, Du hast 50 Millionen Untergruppen je Hauptgruppe und 100 Hauptgruppen, dann wird erst einmal 100 * 50 Millionen Datensätze durchnummeriert, um dann alle bis auf 100 * 5 Records wegzuwerfen.
 
Danke für die Erklärung :)
Mein Provider bietet nur mysql als Datenbank an.
Die zweite Lösung habe ich auch ausprobiert, liefert leider den gleichen Fehler
sql Fehler(1064)..... near 'foo as (select *, row_number() over(partition by h1 order by u1) from edewolf) s'
 
gut, WITH-Abfragen kann MySQL auch nicht, mußt Du umschreiben zu:

von: with x as (select ...) select ... from x
zu: select ... from (select ...) as ax

Nächste Hürde: Window-Funktionen. Kann sein, daß bei Deinem Provider das auch nicht geht. Kommt auf die Version an. MySQL ist halt ...
 
Danke für Deine Geduld :)

Habe es so geschrieben, geht aber nicht

(select *, row_number() over(partition by h1 order by u1) from edewolf) from select * as foo where row_number <= 5
 
Werbung:
Zurück
Oben