Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Firebird 3.0 Order mit Feldname bei Union (https://www.delphipraxis.net/208534-firebird-3-0-order-mit-feldname-bei-union.html)

Kostas 11. Aug 2021 21:14

Datenbank: Firebird • Version: 3.0 • Zugriff über: FIREDAC

Firebird 3.0 Order mit Feldname bei Union
 
Hallo Zusammen,

sorry für den blöden Titel.

Ich habe ein Select
Code:
SELECT *
FROM TABLE1

UNION

SELECT *
FROM TABLE2

ORDER BY 18
Ich habe in ein SELECT * mit mehreren Tabellen die über Union gebunden sind. Am Ende soll sortiert werden. Bei Union funktioniert, zumindest nach meinem Wissen die Sortierung über Feldnamen nicht. Ich kann jedoch nach Feldnummer gehen ORDER BY 18.
Das hat leider ein großen Haken. Wenn ich in den Tabellen Felder hinzufügen würde, könnte sich die FeldNr verschieben und zum falschen Ergebnis führen. Der Feldname wäre hier sicherer.

Hat jemand eine Idee?

Gruß Kostas

Delphi.Narium 11. Aug 2021 21:46

AW: Firebird 3.0 Order mit Feldname bei Union
 
SQL-Code:
select * from (
  SELECT *
  FROM TABLE1
  UNION
  SELECT *
  FROM TABLE2
)
ORDER BY feldname

jobo 12. Aug 2021 05:19

AW: Firebird 3.0 Order mit Feldname bei Union
 
An der Stelle kann man auch sehr schön mit Views arbeiten. (Wie an vielen anderen Stellen auch)
Abgesehen von Aspekten wie Interfacing, diesem Hilfskonstrukt oben und ähnlichen Punkten, bietet ein View bei einem beliebig komplexen Select Statement schon einen Gewinn, wenn es mehr als einmal im Programm aufgerufen wird.

hoika 12. Aug 2021 07:03

AW: Firebird 3.0 Order mit Feldname bei Union
 
Hallo,
sind denn die Feldnamen in den Tabellen gleich?

IBExpert 12. Aug 2021 07:28

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von Kostas (Beitrag 1493496)
Code:
SELECT *
FROM TABLE1

UNION

SELECT *
FROM TABLE2

ORDER BY 18
Der Feldname wäre hier sicherer.

Hat jemand eine Idee?

Der Feldname ist nicht nur da sicherer, sondern auch da zu benutzen, wo du bisher dir mit * das leben einfach machst

Sobald eine der Tabellen in rdb$relation_fields auch nur eine andere Reihenfolge bekommt, wird dir deine
Konstruktion Felder zusammenbauen, die nix mitienander zu tun haben, kann auch dann zB die Spalte
18 sein, nach der zufälig gerade sortieren willst. Die reihenfolge ändert man zwar nicht zufällig,
aber wenn doch, hast du einen rattenschwanz an problemen. Wenn nur eines der beiden Tabellen neue Felder bekommt,
wird die Anweisung eh fehlerhaft sein und nicht ausgeführt werden können.

Löse am besten das Problem gleich da wo es weit größer werden wird als nur bei dem Komfort. im Order by lesbarere
Namen zu haben.

Interaktiv einfach mal mit select * aubzurufen, was da kommt, ist immer legitim, in einer dauerhaft genutzen
SQL Anweisung sollte das immer vermieden werden.

Kostas 12. Aug 2021 08:38

AW: Firebird 3.0 Order mit Feldname bei Union
 
Hallo Holger,

ich wende im normalen Betrieb sehr sehr selten SELECT *. In diesem Fall hat es einen Grund. Es geht um einen Vorgang der alle Daten aller Tabellen bei Neuanlage und Änderung als JSON exportiert. Damit der Exporter immer zuverlässig funktioniert, auch wenn Felder neu hinzugekommen oder entfernt wurden, arbeitet der Prozess mit SELECT * Teilweise sogar generalisiert wobei der Tabellennamen über ein Makro übergeben wird. NUR in ein paar Tabellen habe ich eine Sonderbehandlung. Das UNION bindet ein paar Tabellen mit gleicher Struktur oder dieselbe Tabelle mit unterschiedlichem WHERE. Die Anzahl der Felder sind also immer garantiert identisch und wenn nicht, dann darf es zu einer Exception kommen, denn dann habe ich geschlafen.

Gruß Kostas

Kostas 12. Aug 2021 08:39

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von hoika (Beitrag 1493504)
Hallo,
sind denn die Feldnamen in den Tabellen gleich?

Ja, alle Selects des UNION haben dieselbe Struktur. Dafür sorge ich... normalerweise :-)

Gruß Kostas

dataspider 12. Aug 2021 09:50

AW: Firebird 3.0 Order mit Feldname bei Union
 
Ich nache da immer noch ein

Code:
Select Feldliste from (
  DeinUnionSelect
)
order by ...
drumrum. (Derived tables)

Frank

:oops:, der wurde ja bereits erwähnt...

Kostas 12. Aug 2021 10:01

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von dataspider (Beitrag 1493514)
Ich nache da immer noch ein

Code:
Select Feldliste from (
  DeinUnionSelect
)
order by ...
drumrum. (Derived tables)

Frank

:oops:, der wurde ja bereits erwähnt...

Hallo Frank,

perfekt genau so funktionierts.

Code:
SELECT * FROM (
   SELECT *
   FROM TABLE1

   UNION

   SELECT *
   FROM TABLE2
)

ORDER BY FELDNAME
Tausend Dank.

Delphi.Narium 12. Aug 2021 10:09

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von Kostas (Beitrag 1493508)
Das UNION bindet ein paar Tabellen mit gleicher Struktur oder dieselbe Tabelle mit unterschiedlichem WHERE.

Dann spricht absolut nichts dagegen, auf den Stern zu verzichten und die Spalten aufzuführen, das geht dann sogar per Copy&Paste.

Grundsätzlich halte ich die Nutzung von Select * in Programmen (egal mit welcher Begründung) für fahrlässig.
SQL-Code:
SELECT Spalte1, Spalte2, und, weitere, Spalten
FROM TABLE1

UNION

SELECT Spalte1, Spalte2, und, weitere, Spalten
FROM TABLE2

ORDER BY Und
funktioniert unter FireBird nicht.

Da müsste es korrekterweise dann eher
SQL-Code:
SELECT Spalte1, Spalte2, und, weitere, Spalten from (
  SELECT Spalte1, Spalte2, und, weitere, Spalten
  FROM TABLE1
  UNION
  SELECT Spalte1, Spalte2, und, weitere, Spalten
  FROM TABLE2
)
ORDER BY Und
heißen.

Ändern sich (warum auch immer) mal die Spalten in einer der Tabellen und nehmen wir an, dass es sich immer um Spalten vom Typ Integer handelt, dann funktioniert bei einem * im Select auch sinngemäß sowas:
SQL-Code:
SELECT Sum(Spalte1) as A, Sum(Spalte2) as b, Sum(und) as c, Max(weitere) as d, Spalten from (
  SELECT Spalte1, Spalte2, und, weitere, Spalten
  FROM TABLE1
  UNION
  SELECT und, Spalte1, weitere, Spalte2, Spalten
  FROM TABLE2
)
Group by a,b,c,d
ORDER BY Spalten
Das Gleiche mit Stern
SQL-Code:
SELECT Sum(Spalte1) as A, Sum(Spalte2) as b, Sum(und) as c, Max(weitere) as d, Spalten from (
  SELECT *
  FROM TABLE1
  UNION
  SELECT *
  FROM TABLE2
)
Group by a,b,c,d
ORDER BY Spalten
wird auch funktionieren.

Das kann dann durchaus auch mal in eine Art "Zufallsgenerator" ausarten, bei dem man zwar merkt, dass das Ergebnis irgendwie nicht hinhaut, aber bei der Ursachenforschung wird das dann verdammt haarig.

Und wenn "on the fly" bei unterschiedlichen Datentypen an einer bestimmten Spaltenposition von der Datenbank eine Typkonvertierung erfolgen kann, dann funktioniert das Konstrukt via Select * immer noch.
SQL-Code:
SELECT VarChar, VarChar, Integer, VarChar, Integer from (
  SELECT VarChar, VarChar, Integer, VarChar, Integer FROM TABLE1
  UNION
  SELECT Integer, Integer, Integer, Integer, Integer FROM TABLE2
  UNION
  SELECT VarChar, VarChar, VarChar, VarChar, VarChar FROM TABLE3
)
ORDER BY Und
wird datenbankseitig problemlos verarbeitet.

Nur bei unterschiedlichen Spaltenzahlen wird es einen Fehler geben.

Auf ein
Zitat:

Zitat von Kostas
Dafür sorge ich... normalerweise

verlasse ich mit grundsätzlich nicht ;-)

Oder anders formuliert: Ein Select * in einem Programm geht grundsätzlich nicht durch die Qualitätsprüfung.

jobo 13. Aug 2021 05:27

AW: Firebird 3.0 Order mit Feldname bei Union
 
Die Select * Frage innerhalb einer Union Konstruktion scheint mir sehr schräg. (Es ging ja um das Order by)
Ich bin davon ausgegangen, dass die * Clause lediglich im Beispiel aus Bequemlichkeit aufgeführt wurde und da nebensächlich ist.

Es sieht aber anders aus und ich frage mich wieso.
Ein Union Abfrage ist von "Natur aus" dazu da, eine einheitliche Menge aus unterschiedlich strukturierten Daten zu bilden. Eine unterschiedliche Struktur der Teilmengen führt aber zwangsläufig dazu, dass mit expliziter Angabe von Feldnamen gearbeitet werden muss.
Wenn nicht, gibt es keine unterschiedliche Struktur, dann brauche ich auch kein Union.

Zuerst wäre da die "gleiche Tabelle mit unterschiedlichen Where Clauses", das gehört m.E. in eine Abfrage mit geoderten Where Clauses.

Dann unterschiedliche Tabellen mit gleicher Struktur: das "müffelt" nach "meineDaten2020", "meineDaten2019", meine "DatenLaufendesJahr" usw.
Solche "Konstruktionen" sind am ehesten eine Designschwäche, weil z.B. die Jahresdimension in die Haupttabelle selbst gehört und vermeintliche Vorteile dieser Vorgehensweise auf lange Sicht eine fürchterliche Pfriemelei ergeben, nämlich wenn die Mengen, die eigentlich zusammen gehören an verschiedenen Stellen wieder vereinigt werden müssen. Es ist eine brauchbare Vorgehensweise dafür zu Sorgen, dass einem nie die Arbeit ausgeht und statistische Abfragen und Reports immer den Zweifel in sich tragen, ob auch alle Daten dabei berücksichtigt wurden. Sehr schön am Beispiel besonders, wenn Geschäftsjahr und Datumsjahr nicht deckungsgleich sind.
Häufiges Argument für diese Zerlegung von Tabellen ist auch das Thema Performance. Das sollte aber erst ab deutlich vielen Millionen von Datensätzen tatsächlich relevant werden und wird wenn nötig mit Partitionierung gelöst.

Ein Select * für adhoc Geschichten ist immer okay. Wenn man es systematisch und abgesichert einsetzt, z.B. in bestimmten View Schichten z.B. auch. In einem Union View ist es sehr ungewöhnlich bzw. fraglich.

Jasocul 13. Aug 2021 06:36

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von jobo (Beitrag 1493550)
Wenn nicht, gibt es keine unterschiedliche Struktur, dann brauche ich auch kein Union.

Zuerst wäre da die "gleiche Tabelle mit unterschiedlichen Where Clauses", das gehört m.E. in eine Abfrage mit geoderten Where Clauses.

"geodert" musste ich zweimal lesen :lol:
Du hast offensichtlich noch nicht mit großen Datenmengen gearbeitet, die im "where" ein "or" benötigen. Genau in solchen Fällen ist ein "union" (besser ein "union all") mit der/den selben Tabelle(n) durchaus sinnvoll, um Performance-Probleme zu vermeiden.
Aber auch dann halte ich ein "select *" nicht für sinnvoll.

Delphi.Narium 13. Aug 2021 08:03

AW: Firebird 3.0 Order mit Feldname bei Union
 
Wäre denn da dann nicht eher ein "Union All" sinnvoller?

Union sortiert und entfernt Duplikate.

Union All hängt die Ergebnisse einfach aneinander und ist dadurch auch schneller.

Und wenn ich eine Tabelle mit unterschiedlichen Whereklauseln habe, sollte es keine Duplikate geben, wenn doch, hab' ich eher ein Logikproblem in den Wherebedingungen, als die Erfordernis, diese Duplikate per Union zu entfernen.

Die Verwendung von Union ist bei mir eben ebenso fraglich, wie ein Distinct in einem unvollständig ausformulierten Join, der dadurch zu Dubletten führt.

Und ja: Für beide Konstrukte, Union und Distinct, gibt es zuweilen Ausnahmesituationen, in denen deren Verwendung sinnvoll sein kann. Aber bitte immer erst dann, wenn es anders nicht geht. Erfahrungsgemäß ist "es geht auch ohne" auch performanter, da die Datenbank nicht erst mehr oder weniger große Datenmengen zusammensuchen und die dann anschließend auf Eindeutigkeit trimmen muss.

Bei kleinen Datenmengen mag das nicht unbedingt ins Gewicht fallen, bei etlichen dutzend Millionen Datensätzen freut sich der Temptablespace dann aber schon über eine geringere Belastung, derweil, dort fängt es dann an, deutlich in Richtung "suboptimale" Performanz zu gehen.

dataspider 13. Aug 2021 11:00

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1493552)
Wäre denn da dann nicht eher ein "Union All" sinnvoller?

:thumb: Das sehe ich genau so...

Jasocul 13. Aug 2021 12:08

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1493552)
Wäre denn da dann nicht eher ein "Union All" sinnvoller?

Stimmt. Wenn schon, dann "union all". Ist bei mir auch immer so, wenn solche Abfragen erstellt werden müssen.

jobo 13. Aug 2021 16:31

AW: Firebird 3.0 Order mit Feldname bei Union
 
Zitat:

Zitat von Jasocul (Beitrag 1493551)
Zitat:

Zitat von jobo (Beitrag 1493550)
Wenn nicht, gibt es keine unterschiedliche Struktur, dann brauche ich auch kein Union.

Zuerst wäre da die "gleiche Tabelle mit unterschiedlichen Where Clauses", das gehört m.E. in eine Abfrage mit geoderten Where Clauses.

"geodert" musste ich zweimal lesen :lol:
Du hast offensichtlich noch nicht mit großen Datenmengen gearbeitet, die im "where" ein "or" benötigen. Genau in solchen Fällen ist ein "union" (besser ein "union all") mit der/den selben Tabelle(n) durchaus sinnvoll, um Performance-Probleme zu vermeiden.
Aber auch dann halte ich ein "select *" nicht für sinnvoll.

geodert, ja, keine Geographie. Das nächste Mal nehm ich ein Bindestrich dazu :)

Naja, was ist groß? 2 stellige Millionenwerte ist mein Erfahrungshorizont, was Systene angeht, an denen ich entwickelt habe, ohne solche Konstruktionen, noch zu HDD Zeiten.
Und ich wüsste nicht, warum eine Engine ein OR schlechter behandeln sollte als ein Union (all).

Ich kann es auch anders formulieren:
Bevor man zu sowas greift, sollte man gründlich überlegen, welchen Aufwand es nach sich zieht (Codepflege), welche Risiken (Lücken in der Codepflege) und welche anderen Maßnahmen man ergreifen kann (Partitioning, Tuning, Optimizer Hints, ..) Kommt ja alles sicher auch etwas auf den Anbieter (oder Version) des DB Sstems an. Und nur ums explizit zu sagen: Partitioning ist ja im Prinzip eine Art Union All, nur es erlaubt logisch einen transparenten Zugriff, trotz interner Aufteilung der Tabelle nach irgendwelchen Kriterien. Wenn die DB das kann, warum soll ich es dann zu Fuß machen?

Frickler 16. Aug 2021 11:35

AW: Firebird 3.0 Order mit Feldname bei Union
 
Man kann ja auch im Vorfeld die Feldliste holen und testen, ob gleich:
(oder halt die SQL-Anweisung als String zusammenbauen und ausführen)
Code:
SET TERM ^;

CREATE OR ALTER PROCEDURE sp_get_columns

  tablename VARCHAR(30),
  uppercase BOOLEAN = true
)
RETURNS
(
  feldliste VARCHAR(2000)
)
AS
  DECLARE feldname VARCHAR(40) = '';
BEGIN
  feldliste = '';
  FOR SELECT rdb$field_name FROM rdb$relation_fields
      WHERE UPPER(rdb$relation_name) = UPPER(:tablename)
      ORDER BY rdb$field_position
  INTO :feldname
  DO BEGIN
    IF (feldliste <> '') THEN feldliste = feldliste || ',';
    feldliste = feldliste || TRIM(feldname);
  END
  IF (NOT uppercase) THEN feldliste = LOWER(feldliste);
END^

SET TERM ;^

kettyedith 18. Aug 2021 09:44

AW: Firebird 3.0 Order mit Feldname bei Union
 
The column name appears in an aggregate function call select from rdb$collations order by 3, 2.Being able to order the results of a UNION query using "field names" [CORE1505] #1920. Open.So you only use UNION ALL to avoid sorting if you know that there are no duplicate rows in the tables). Everything new in Firebird SQL since InterBase 6. Paul Vinkenoog et al. ... Views can infer column names from derived tables or GROUP BY.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:48 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz