Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Bekomme Inner Joins nicht hin (https://www.delphipraxis.net/199006-bekomme-inner-joins-nicht-hin.html)

Der schöne Günther 18. Dez 2018 15:47

Datenbank: Ms-Sql • Version: 2012 • Zugriff über: --

Bekomme Inner Joins nicht hin
 
Eins vorweg: Ich habe mit Datenbanken extrem wenig Erfahrung.

Ich habe in meiner Datenbank "Items". Wenn diese verändert werden soll der alte Stand nicht gelöscht werden, sondern ein neuer hinzugefügt werden wo die Revisionsnummer höher ist.

Meine Struktur sieht so aus:

Item:
NameTypAnmerkung
id TEXT 
rev INT Fkey auf Item_Rev.id
Daten1 ? 
Daten2? 

Item_Rev:
NameTypAnmerkung
id INT (AutoInc)
changeTimestamp DATETIME 
changeComment TEXT 


Dann habe ich das auf meinem PC in einer Sqlite-Datenbank umgesetzt. Folgende Query sollte mir alle Items in der neusten Revision liefern:

Code:
SELECT
      id, Daten1, Daten2, MAX(changeTimestamp) changeTimestamp, changeComment
FROM Item a INNER JOIN (
       SELECT id fkey, MAX(changeTimestamp) changeTimestamp, changeComment
       FROM Item_Rev      
       GROUP BY fkey, changeComment
 ) b ON (a.rev = b.fkey)
 GROUP BY id
Gesagt, getan. In SQLite kommt genau heraus was ich mir vorgestellt habe 😎👍


Dann habe ich das auf MS-SQL umgesetzt. Die Query so nimmt er nicht an, er meint
Zitat:

SQL-Fehler [207] [S0001]: Ungültiger Spaltenname 'fkey'.
. Gut, dann habe ich das GROUP BY folgendermaßen abgeändert:
Code:
SELECT
      id, Daten1, Daten2, MAX(changeTimestamp) changeTimestamp, changeComment
FROM Item a INNER JOIN (
       SELECT id AS fkey, MAX(changeTimestamp) changeTimestamp, changeComment
       FROM Item_Rev      
       GROUP BY id, changeComment
 ) b ON (a.rev = b.fkey)
 GROUP BY id
Daraufhin meint er
Zitat:

SQL-Fehler [8120] [S0001]: Die Item.Daten1-Spalte ist in der Auswahlliste ungültig, da sie nicht in einer Aggregatfunktion und nicht in der GROUP BY-Klausel enthalten ist.
Gut, dann füge ich die auch noch an:

Code:
SELECT
      id, Daten1, Daten2, MAX(changeTimestamp) changeTimestamp, changeComment
FROM Item a INNER JOIN (
       SELECT id AS fkey, MAX(changeTimestamp) changeTimestamp, changeComment
       FROM Item_Rev      
       GROUP BY id, changeComment
 ) b ON (a.rev = b.fkey)
 GROUP BY id, Daten1, Daten2, changeComment
Das Problem: Ich erhalte hier die Items in allen ihren Revisionen. Es ist das gleiche als hätte ich geschrieben

Code:
SELECT [Spalten...] From Item JOIN Item_Rev ON (Item.rev = Item_Rev.id)
Was läuft hier falsch? Bin ich bei der "fkey"-Sache schon falsch abgebogen? Wenn SQLite etwas kann, dann muss MS-SQL das doch schon lange können, oder?

Uwe Raabe 18. Dez 2018 16:02

AW: Bekomme Inner Joins nicht hin
 
So ganz steige ich da noch nicht durch. Das Inner-Select lautet
Code:
SELECT id AS fkey, MAX(changeTimestamp) changeTimestamp, changeComment
FROM Item_Rev    
GROUP BY id, changeComment
Dabei ist id laut Anmerkung ein AutoInc-Feld - also eindeutig. Ein Group By über ein eindeutiges AutoInc-Feld ist aber irgendwie witzlos, da jeder Feldwert ja eh nur einmal vorkommen kann. Du kannst ja mal einfach nur diese Query ausführen und wirst vermutlich alle Datensätze zurückbekommen.

Der schöne Günther 18. Dez 2018 16:07

AW: Bekomme Inner Joins nicht hin
 
Ja, ich bekomme praktisch alles. Beide Tabellen haben eine Spalte
Delphi-Quellcode:
id
. Ich möchte natürlich nicht nach dem AutoInc-id, sondern nach der Text-ID aus Tabelle "item" gruppieren.

SQLite scheint das richtig zu machen. Wenn ich in MS-SQL jetzt aus "GROUP BY id" ein "GROUP BY Item.id" mache sagt er mir
Zitat:

SQL-Fehler [4104] [S0001]: Der mehrteilige Bezeichner 'Item.id' konnte nicht gebunden werden.

mkinzler 18. Dez 2018 16:29

AW: Bekomme Inner Joins nicht hin
 
SQL-Code:
GROUP BY a.id
?

Der schöne Günther 18. Dez 2018 16:42

AW: Bekomme Inner Joins nicht hin
 
Nope, ob mit a. oder ohne macht keinen Unterschied.

Ich verstehe das nicht. War der Sinn von SQL nicht dass man es über verschiedene Datenbank-Systeme hinweg verwenden könne?

ibp 18. Dez 2018 17:05

AW: Bekomme Inner Joins nicht hin
 
Code:
SELECT
      id, Daten1, Daten2, MAX(changeTimestamp) changeTimestamp, changeComment
FROM Item a INNER JOIN (
       SELECT id AS fkey, MAX(changeTimestamp) changeTimestamp, changeComment
       FROM Item_Rev    
       GROUP BY id, changeComment
 ) b ON (a.rev = b.fkey)
 GROUP BY id, Daten1, Daten2, changeComment
vielleicht so:

Code:
SELECT
      a.rev, a.Daten1, a.Daten2, MAX(b.changeTimestamp) changeTimestamp, b.changeComment
FROM Item a
INNER JOIN Item_Rev b ON (a.rev = b.id)
GROUP BY a.Daten1, a.Daten2, b.changeComment

Delphi.Narium 18. Dez 2018 17:10

AW: Bekomme Inner Joins nicht hin
 
Höchste Revisionsnummer zum Item suchen:
SQL-Code:
SELECT id, Max(rev) from Item group by ID


Das folgende führt nicht zum gewünschten Ergebnis, da hier das höchste Änderungsdatum zu ID UND Änderungskommentar gesucht wird. Das kann nur dann zum "annähernd" gewünschten Ergebnis führen, wenn alle Kommentare gleich sind.
SQL-Code:
SELECT id AS fkey, MAX(changeTimestamp) changeTimestamp, changeComment
FROM Item_Rev    
GROUP BY id, changeComment
Eventuell so?
SQL-Code:
select
  Item.Id,
  Item.Rev,
  Item.Daten1,
  Item.Daten2,
  Item_Rev.changeTimestamp,
  Item_Rev.changeComment
from
  Item,
  Item_Rev,
  (SELECT Id, Max(Rev) As Rev from Item group by ID) Max_Rev
where Item.rev = Item_Rev.id
and Item.ID = Max_Rev.ID
and Item.Rev = Max_Rev.Rev
PS: Bin eher ein alter Knacker, deshalb nehme ich lieber die (für mich) leichter lesbare alte Form für Joins.

Der schöne Günther 18. Dez 2018 17:14

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von ibp (Beitrag 1421184)
vielleicht so

Danke, aber dann sagt er
Zitat:

SQL-Fehler [8120] [S0001]: Die Item.rev-Spalte ist in der Auswahlliste ungültig, da sie nicht in einer Aggregatfunktion und nicht in der GROUP BY-Klausel enthalten ist.

MS-SQL ist schon seltsam. Ich denke es jetzt mit einer völlig anders formulierten Query hinbekommen zu haben:

Code:
SELECT * FROM Auftrag JOIN Auftrag_Rev
ON (Auftrag.rev = Auftrag_Rev.id)
WHERE Auftrag.rev in (
   SELECT MAX(rev) rev FROM Auftrag JOIN Auftrag_Rev ON (Auftrag.rev = Auftrag_Rev.id)
   GROUP BY Auftrag.id
   )
;
In SQLite funktioniert das umgekehrt auch. Ist das jetzt geschickt oder eine Performance-Katastrophe? Und was MS-SQL eigentlich für ein Problem mit dem ersten Statement das in SQLite so gut geht?

Irgendwie weiß ich weshalb ich Kontakt mit relationalen Datenbanken so gut wie möglich vermeide...


Update

Zitat:

Zitat von Delphi.Narium (Beitrag 1421185)
PS: Bin eher ein alter Knacker, deshalb nehme ich lieber die (für mich) leichter lesbare alte Form für Joins.

Danke, das scheint auch zu gehen. Und ist wirklich sehr gut lesbar! Und geht auch in SQLite.

Vielen Dank!

Uwe Raabe 18. Dez 2018 17:37

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1421179)
War der Sinn von SQL nicht dass man es über verschiedene Datenbank-Systeme hinweg verwenden könne?

Nein, denn das S in SQL steht nicht für Standard sondern für Structured. Insbesondere gilt für Interoperability and standardization:
Zitat:

SQL implementations are incompatible between vendors and do not necessarily completely follow standards.
Es gibt zwar SQL Standards, aber die definieren in der Regel nur einen kleinsten gemeinsamen Nenner. Es ist mitunter auch gar nicht so leicht zu erkennen, wann man einen solchen Standard verlässt, wenn das aktuelle Konstrukt in der gerade verwendeten Datenbank zufällig noch funktioniert.

Der schöne Günther 18. Dez 2018 17:40

AW: Bekomme Inner Joins nicht hin
 
Danke. Dann fühle ich in meiner Einstellung Bleibe Datenbanken fern solange du kannst ja bestärkt 🤣

mkinzler 18. Dez 2018 17:44

AW: Bekomme Inner Joins nicht hin
 
Und T-SQL ist in vielen Dingen halt "speziell"

Uwe Raabe 18. Dez 2018 17:54

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von mkinzler (Beitrag 1421196)
Und T-SQL ist in vielen Dingen halt "speziell"

SQLite aber auch.

mkinzler 18. Dez 2018 17:58

AW: Bekomme Inner Joins nicht hin
 
Jo.

EmWieMichael 19. Dez 2018 07:14

AW: Bekomme Inner Joins nicht hin
 
Als ausgewiesener NichtSQLGuru habe ich eine Frage zur Datenstruktur:
Warum trennst Du die Daten in zwei Tabellen auf? Wäre es nicht einfacher, die Revisionsdaten DateTime und den Kommentar mit in die Haupttabelle zu nehmen?

Gruß Michael

Der schöne Günther 19. Dez 2018 07:52

AW: Bekomme Inner Joins nicht hin
 
"Einfacher" sicherlich, aber nicht normalisiert.

Vielleicht war es gestern Abend für mich schon zu spät, aber wenn ich es noch richtig im Kopf habe, dann ist das immerhin in dritter Normalform, denn ich habe keine transitive Abhängigkeit.

Hätte ich die Felder "changeTimestamp" und "changeComment" noch mit hereingepackt hätte ich die dritte Normalform nicht, denn Daten1 & Daten2 wären abhängig davon. Wahrscheinlich noch nicht einmal die erste Normalform, denn was haben eigentlich Änderungszeitpunkt und -Kommentar mit einem "Item" an sich zu tun?


http://www.datenbanken-verstehen.de/...ormalisierung/

https://www.php-kurs.com/normalisierung.htm

mkinzler 19. Dez 2018 08:02

AW: Bekomme Inner Joins nicht hin
 
Normalisiert wäre es aber in die andere Richtung.

Eine Revision bezieht sich auf eine Item und nicht umgekehrt.

Der schöne Günther 19. Dez 2018 08:08

AW: Bekomme Inner Joins nicht hin
 
Auch ein Argument. Meine Motivation war eher dass es später evtl. nicht "Item_Rev" sondern nur "Rev" ist. Das eine Revision nicht nur ein Item, sondern evtl. auch Wombatze enthält.

Ich denke sobald ich den Kram halbwegs am laufen habe mache ich noch einmal ein eigenes Thema um die Struktur von euch Profis bewerten zu lassen...

Jumpy 19. Dez 2018 08:23

AW: Bekomme Inner Joins nicht hin
 
Ich finde die Struktur auch Suboptimal, aber sei es wie es sei, ist nicht einfach durch die höchste Rev_ID schon alles bestimmt?

SQL-Code:
Select * From Items
Left Join rev_items b on b.ID=a.rev
Where a.rev=(Select max(rev) From Items Where ID=a.ID)
Rom, viele Wege und so...

Der schöne Günther 19. Dez 2018 08:37

AW: Bekomme Inner Joins nicht hin
 
Ich bin ja noch nicht einmal mit der Syntax klargekommen. Dass man einfach so sagen kann
Delphi-Quellcode:
WHERE x = (Query)
war mir z.B. auch neu.

Das sieht ja schon beschämend einfach aus und scheint zu gehen.

Warum grade Left Join? Das würde Sinn machen wenn man Items ohne Revision hat, aber die gibt es bei mir nicht 😎

rokli 19. Dez 2018 09:39

AW: Bekomme Inner Joins nicht hin
 
Ja, Normalisierung ist wichtig und gut ... aber manchmal steht sie dem flexiblen und raschen Zugriff auf Daten auch ganz schön im Weg. :stupid:

mkinzler 19. Dez 2018 09:46

AW: Bekomme Inner Joins nicht hin
 
Ich sehe in diesem Fall nicht das Problem der Normalisierung sondern das Design der Tabellen

Der schöne Günther 19. Dez 2018 09:58

AW: Bekomme Inner Joins nicht hin
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ok, wir haben schon jetzt ein handfestes Problem? Dann helft mir bitte doch am besten jetzt 😓

Uwe Raabe 19. Dez 2018 10:20

AW: Bekomme Inner Joins nicht hin
 
Ich bin mir nicht sicher, wie diese Aussage zu verstehen ist:
Zitat:

Ich habe in meiner Datenbank "Items". Wenn diese verändert werden soll der alte Stand nicht gelöscht werden, sondern ein neuer hinzugefügt werden wo die Revisionsnummer höher ist.
Wenn du also einen Eintrag in der Tabelle Item veränderst (z.B. Daten1 und/oder Daten2), wird wohl in jedem Fall ein neuer Datensatz in Item-Rev angelegt. Wird in Tabelle Item dann auch ein neuer Eintrag mit derselben ID aber den neuen Daten-Werten und der neuen rev angelegt?

mkinzler 19. Dez 2018 10:26

AW: Bekomme Inner Joins nicht hin
 
Du hast Items, von welchem (1 zu n) Revisionen bestehen.

Item

ID ( PK; autoinc)
DESC (altes Feld ID)
Daten1
Daten2

Rev
ID (PK; autoinc)
Item ( FK auf Tabelle Item Feld ID)
Changed
Comment

Der schöne Günther 19. Dez 2018 10:29

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1421230)
Wird in Tabelle Item dann auch ein neuer Eintrag mit derselben ID aber den neuen Daten-Werten und der neuen rev angelegt?

Ganz genau.

Vorher:
Item:
idrevDaten1Daten2
"ABC/123"1"Waffel"3.14

Item_Rev:
idchangeTimestampchangeComment
12018-12-18"Item angelegt"

Nachher:
Item:
idrevDaten1Daten2
"ABC/123"1"Waffel"3.14
"ABC/123"2"Bohnen und Speck"3.14

Item_Rev:
idchangeTimestampchangeComment
12018-12-18"Item angelegt"
22018-12-19"Wir brauchen unbedingt Bohnen"



Zitat:

Zitat von mkinzler (Beitrag 1421231)
...

Danke für die Alternative. Wo die Vorteile sind muss ich jetzt noch meditieren...

Uwe Raabe 19. Dez 2018 10:44

AW: Bekomme Inner Joins nicht hin
 
Gemäß deinem vorher/nachher Beispiel kannst du die Felder der beiden Tabellen auch in eine Tabelle zusammenfassen. Es existiert zu jedem Item-Datensatz ja auch genau ein Datensatz in Item_Rev. Das macht die Trennung in zwei Tabellen eigentlich überflüssig.

Wenn du das in einer Tabelle realisierst, fällt das Item_Rev.ID Feld ja weg, da es dem Item.rev Feld entspricht. Da das Item.ID Feld aber kein AutoInc-Feld sein kann, bietet sich an, das Item.rev Feld als AutoInc anzulegen, damit die Revisionen automatisch hochgezählt werden. Damit ist gewährleistet, daß neuere Datensätze immer einen höheren rev-Wert haben.

rokli 19. Dez 2018 11:11

AW: Bekomme Inner Joins nicht hin
 
Möglicherweise hilft Dir noch die Info, dass es bei MS SQL einen Feldtyp Namens DATETIME gibt.

Das Feld ANLAGE_DATUM, mit dem Default GEDATE() definiert, verwende ich in quasi jeder Tabelle. Beim anlegen eines Datensatzes sorgt der Konstrukt dafür, dass Du automatisch die genau Datum und Uhrzeit zum Datensatz speicherst.

Der schöne Günther 19. Dez 2018 11:13

AW: Bekomme Inner Joins nicht hin
 
Vielen Dank für die Geduld und Erklärungen bislang.

Ich sehe ein dass man es eigentlich auch in eine Tabelle packen könnte. Ich sehe noch nicht was ich dadurch gewonnen habe - Ich finde es so sehr sympathisch halt ein Feld "rev" zu haben, und sonst nichts als das "Item". Mit Kommentar, Zeitstempel usw. "verunreinige" ich mMn ein bisschen die Tabelle "Item".


Außerdem ist die Tabelle "Item_Rev" völlig neutral gegenüber einem "Item". Eigentlich könnte ich sie sogar "Revisionen" nennen und für alles nutzen, nicht nur Items.

Wenn ich eines Tages noch anfange zu Revisionen z.B. nicht nur einen Freitext-Kommentar sondern einen Benutzernamen zu speichern müsste ich dann auch nur die Tabelle "Revisionen" anpassen - Und nicht alle Tabellen wo etwas revisioniert wird.

rokli 19. Dez 2018 11:15

AW: Bekomme Inner Joins nicht hin
 
Beispiel solch einer Definition MS SQL Server Management Studio

Code:
CREATE TABLE [dbo].[tblName](
   .
   .
   .
   [DatAuf] [datetime] NULL CONSTRAINT [DF_tblName_DatAuf] DEFAULT (getdate()),
   [UsrAuf] [varchar](124) NULL CONSTRAINT [DF_tblName_UsrAuf] DEFAULT ((((('Pc: '+host_name())+'; User: ')+suser_sname())+' - ')+app_name()),
   [DatAen] [datetime] NULL,
   [UsrAen] [varchar](124) NULL,
   .
   . usw

Uwe Raabe 19. Dez 2018 11:36

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von Der schöne Günther (Beitrag 1421236)
Ich sehe ein dass man es eigentlich auch in eine Tabelle packen könnte. Ich sehe noch nicht was ich dadurch gewonnen habe - Ich finde es so sehr sympathisch halt ein Feld "rev" zu haben, und sonst nichts als das "Item". Mit Kommentar, Zeitstempel usw. "verunreinige" ich mMn ein bisschen die Tabelle "Item".

Solange zwischen beiden Tabellen eine 1:1 Beziehung herrscht, ist eine künstliche Trennung der Felder in separate Tabellen und datentechnisch nicht erforderlich.

Zitat:

Zitat von Der schöne Günther (Beitrag 1421236)
Außerdem ist die Tabelle "Item_Rev" völlig neutral gegenüber einem "Item". Eigentlich könnte ich sie sogar "Revisionen" nennen und für alles nutzen, nicht nur Items.

Das würde dann aber der oben genannten 1:1 Beziehung widersprechen. Es gäbe dann nämlich Sätze in "Revisionen", die keinen Partner-Datensatz in "Items" haben.

Zitat:

Zitat von Der schöne Günther (Beitrag 1421236)
Wenn ich eines Tages noch anfange zu Revisionen z.B. nicht nur einen Freitext-Kommentar sondern einen Benutzernamen zu speichern müsste ich dann auch nur die Tabelle "Revisionen" anpassen - Und nicht alle Tabellen wo etwas revisioniert wird.

Es ist ziemlich aussichtslos, eine DB-Struktur auf eventuell denkbare, zukünftige Anforderungen hin zu entwerfen. Wir können auch nur das beurteilen, was du uns hier beschreibst - nicht das, was du eventuell in Zukunft vorhast.

Jumpy 19. Dez 2018 11:42

AW: Bekomme Inner Joins nicht hin
 
Wir arbeiten hier mit einer Software mit über 1000 Tabellen, alls großteils historisch gesteuert, das ist ja sowas ähnliches wie deine Revisionen.
Die Infos dazu stehen jeweils in der Tabelle selber, in unserem Fall eine Art GültigVON und GültigBis Datum für den Datensatz.

Der Vorteil ist, wie du selber schon gemerkt hast, das die Abfragen einfacher werden, wenn du wissen willst, was der gerade aktuell gültige Datensatz ist. Wenn du daher aktuelle Items mit aktuellen Foos joinen willst und sowohl für Items als auch Foos musst du die Revisionstabelle dazu joinen oder abfragen, wird es schnell unübersichtlich und evtl. auch langsam.

Allerdings ist deine Intention mit der Revisionstabelle natürlich auch sinnvoll und dafür gibt es bei uns ein ChangeLog/ChangeHistory Tabellen Konstrukt, dass zwar nicht optimal (gewachsene Struktur) ist, aber man kann sehen wer hat was wann geändert (leider nicht warum).

mkinzler 19. Dez 2018 11:46

AW: Bekomme Inner Joins nicht hin
 
Grundsätzlich ist Normalsisierung (bzw. SnowFlaking) sinnvoll. Man kann ja auch einen (Join-)View erstellen.

jfheins 19. Dez 2018 12:05

AW: Bekomme Inner Joins nicht hin
 
Um dir noch etwas Lesestoff zu geben: Du hast da eine SCD (Slowly Changing Dimension)
Es gibt verschiedene Ansätze, wenn du die Historie behalten möchtest nur Typ 2 oder 3.

Bei Typ 2 kannst du die nicht mehr gültigen Daten in eine eigene Tabelle auslagern, muss aber nicht. Wichtiger wäre, dass du immer ein "Gültig bis" Datum drin speicherst, wenn das NULL ist, ist diese Zeile gültig.
Wenn du den Primary Key nicht auf dieses Feld erweitern möchtest, würde ich es auf zwei Tabellen splitten - siehe Beitrag von mkinzer:
Zitat:

Zitat von mkinzler (Beitrag 1421231)
Du hast Items, von welchem (1 zu n) Revisionen bestehen.

Und so allgemein solltest du dir überlegen, nicht nur einen Kommentar zu speichern, sonder auch, was sich geändert hat ;-)

jobo 19. Dez 2018 12:24

AW: Bekomme Inner Joins nicht hin
 
Mein Senf:
Ich versteh die Trennung, die (eigene) innere Ordnung der Dinge, die man erhalten möchte.
Das ist auch legitim und m.E. ebenso legitim, an dieser stelle "Insider Wissen" einzusetzen und bereits eine Trennung vorzunehmen, wenn sie faktisch in der bevorstehenden Version noch nicht benötigt wird.
Normalisierung ist kein Selbstzweck, sondern hat primär einen ganz simplen und wichtigen Grund:
Konsistenz

Wenn man sein Datenmodell so konstruiert, dass Konstistenz (garantiert) gewahrt bleibt, hat man nichts verkehrt gemacht. Den Zusatzaufwand treibt man aber nicht aus Vergnügen, es sollte schon irgendwelche Gründe geben, die nicht nur einem selbst bekannt (und akzeptiert) sind.

Bei einer Historisierung oder Revisionen hier wäre es m.E. wichtig dafür zu sorgen, das ein Basiszugriff auf aktuell gültige Daten per Default erfolgt. Das würde hier heißen, mit Views zu arbeiten, die Altdaten automatisch ausblenden.
Ausnahme wäre ggF. wenn die Historie teil des Business Case ist und irgendwelche Spezialisten ständig mit verschiedenen Ständen arbeiten (müssen).


Gerade erst gesehen:
Ist das vielleicht nur eine Fake Frage, weil DSG hier
https://www.delphipraxis.net/199015-...ml#post1421208
nicht weiter kommt?

p80286 19. Dez 2018 14:29

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1421238)
Es ist ziemlich aussichtslos, eine DB-Struktur auf eventuell denkbare, zukünftige Anforderungen hin zu entwerfen. Wir können auch nur das beurteilen, was du uns hier beschreibst - nicht das, was du eventuell in Zukunft vorhast.

Einspruch, nur wenn definitiv ausgeschlossen ist, daß es keine zwei oder mehr Revisionen zu einem Item gibt, dann könnte man über eine Tabelle nachdenken. Und wenn man eine 1:n Beziehung von vorneherein in Betracht zieht, ist man auf der sicheren Seite.
Ausnahmen die es nieee geben wird sind zum :kotz:

Gruß
K-H

Uwe Raabe 19. Dez 2018 15:06

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von p80286 (Beitrag 1421257)
Einspruch, nur wenn definitiv ausgeschlossen ist, daß es keine zwei oder mehr Revisionen zu einem Item gibt, dann könnte man über eine Tabelle nachdenken.

Deswegen ja meine Frage. So wie ich das verstanden habe, wird zu jeder neuen Revision je ein Datensatz in Item und Item_Rev angelegt und mit Item.rev = Item_rev.ID verknüpft. Ohne zusätzliche Spezifikationen ist das definitiv eine 1:1 Beziehung und die kann problemlos in einer Tabelle zusammengefasst werden.

Was die sichere Seite betrifft, steht man dort sehr häufig auch nur auf dünnem Eis. Analog zu Premature Optimization fällt das auch sehr leicht in die Kategorie Over-Engineering oder wie man hier landläufig sagt: unnötig kompliziert.

jobo 19. Dez 2018 15:36

AW: Bekomme Inner Joins nicht hin
 
apropos 1:1
wie sind die Beispieldaten zu verstehen, die Werte für REV>Id passen m.E. nicht, Tippfehler oder Verständnisfehler bei mir?

https://www.delphipraxis.net/1421232-post25.html

joachimd 19. Dez 2018 16:09

AW: Bekomme Inner Joins nicht hin
 
Ich würde ja ganz stumpf eine "Master" Tabelle (item) machen, in welcher die aktuellen Items drin stehen. Und zwar immer in der neuesten Revision - zur Not auch noch mit Kommentar, warum diese Revision nötig war, dem Benutzernamen und einem Zeitstempel.
Daneben eine "History" Tabelle (item_history), welche prinzipiell gleich aufgebaut ist.
Bei jeder Änderung in der Master Tabelle wird der alte Record in die History Tabelle übertragen und fertig.

Ein select auf die Master Tabelle liefert die aktuellen items.
Wenn die verschiedenen Revisionen gebraucht werden, kommt ein UNION mit der History Tabelle.

Der schöne Günther 19. Dez 2018 16:10

AW: Bekomme Inner Joins nicht hin
 
Zitat:

Zitat von jobo (Beitrag 1421272)
apropos 1:1
wie sind die Beispieldaten zu verstehen, die Werte für REV>Id passen m.E. nicht, Tippfehler oder Verständnisfehler bei mir?

https://www.delphipraxis.net/1421232-post25.html

Sorry, Tippfehler von mir. Habe es korrigiert.

jobo 20. Dez 2018 07:34

AW: Bekomme Inner Joins nicht hin
 
Hier sind 3 Varianten ohne Anspruch auf Vollständigkeit usw:
Code:
-- nur max(id) wenn garantiert(!) ist, dass sie eindeutig, aufsteigend ist (faule Lösung)
-- geht "immer" (Syntax)
select a.*, r.*
  from item a
  join (select max(id) fkey from Item_Rev) b
    on a.rev = b.fkey
  join item_rev r
    on a.rev = r.id;
 

-- erst max(timestamp), darüber die zugehörige ID holen-Reihenfolge nun egal-  ("ordentliche" Lösung)
--   ordentlich halt*, Syntax geht auch immer
select a.*, r.*
  from item a
  join (select id
          from item_rev ri
          join (select max(changetimestamp) x from Item_Rev) rx
            on ri.changetimestamp = rx.x) b
    on a.rev = b.id
  join item_rev r
    on a.rev = r.id;
 
-- top n, logisch sauber, vermeidet Group ganz, trendy
--   bin mir nicht ganz sicher, aber es wäre eine typische MS Lösung, die relativ früh (als erste?) die TOP Funktion eingeführt hatten
--   ich würde mal sagen, eine gute Lösung, m.E. ohne Group sozusagen straight forward, aber syntaktisch nicht sehr kompatibel
--      (ersetze "top n" durch "limit n" o.ä. für andere Systeme)
select a.*, r.*
  from Item a
  join (select top 1 id from Item_Rev
         order by changetimestamp desc) b
    on a.rev = b.id
  join item_rev r
    on a.rev = r.id;

zu *
Alles ist relativ. Diese Lösung vermeidet das vielleicht etwas theoretische ID Problem (aufsteigend=chronologische ID= höchste Revision).
Aber was ist, wenn changetimestamp sich später (per Trigger) ändert, weil z.B. rein Rechtschreibfehler korrigiert wurde?


Die anfangs von Dir gefundene SQLite Variante hat mich mehr als überrascht und stark an das mySQL Desaster erinnert.
Ich war bis gerade der Meinung, mySQL seien die Einzigen, die sowas gefährliches "anbieten". Deren Group By Syntax war angetreten, ~ohne weiteres~ eine richtige Antwort zu liefern, es kommt dort aber meist Schrott raus, wenn man sich nicht an die Spielregeln hält. SQLite ist dann wohl Nr. 2 in dieser Heldenliste.
Ein Zitat aus deren Hilfe
Zitat:

Side note: Bare columns in an aggregate queries. ...
... and so in many cases the value for "b" is undefined...
Das Ergebnis ist also undefiniert!!! Dein (richtiges) Ergebnis wäre nach dieser Beschreibung also Zufall?
Es geht noch weiter in der Hilfe. Dort wird beschrieben, dass nur bei min und max etwas besonderes gemacht wird, was dann tatsächlich Dein Ergebnis erklärt. Eine sehr bequeme "Abkürzung" für den Entwickler von etwas SQL Text, aber tatsächlich weit weg vom Standard. Ich find besonders den ersten Teil gefährlich. Würde ich mich nicht dran gewöhnen. Vielleicht hast Du selbst diese Doku gelesen und warst der Meinung, so gehört sich das ..

Und wo ich dabei bin. was das Thema "kompatibel" angeht:
Es gibt die verschiendenen ANSI SQL Versionen von 86 bis 2016. Daran hält sich leider niemand vollständig (Was m.E. schlimmer klingt, als es ist, da man bei sowas offenbar schon die wichtigsten Dinge angeht)
Den Wunsch nach Kompatibilität versteh ich gut, aber es ist wie bei verschiedenen Pascal Dialekten, eben nicht alles kompatibel.
SQLite ist m.E. ein Exot, weil es ganz klar anders positioniert ist, als MSSQL oder andere große. Auf der Ebene am ehesten vergleichbar mit dem embedded Part von Firebird, aber eben nur mit dem. Ebenso exotisch der lockere Umgang mit Typen, low concurrency Ansatz, ..
MSSQL ist da gefühlt eher Standard, aber fett und reich genug, eigene Features vor den Standard zu stellen. Das gilt ähnlich für die anderen Kommerzanbieter. Gewollt sind am ehesten die open source Systeme bemüht, Standards einzuhalten, hier fehlen dann leider oft die Ressourcen. Postgres legt allerdings sehr großen Wert auf die ANSI-SQL Normen und kriegt das auch ganz gut hin.
In der Praxis geschieht es häufig, dass man sich für eine Syntax entlang der Doku des verwendeten Systems entscheidet und dabei nicht Standard gemäß formuliert, obwohl die DB es verstehen würde. Die Mohrrübe ist dabei oft auch eine kleine Extraportion Komfort oder Funktionalität. "Alte Hasen" haben da den kleinen Vorteil, dass sie aus Gewohnheit "gut abgehangenes" SQL verwenden. (Was nicht immer wirklich ein Vorteil sein muss, weil sie die Mohrrübe gar nicht sehen).

Zum "Problem"
Für Group By gibt es eine Faustregel, mit der man gut fährt:
Alle nicht aggregierten Felder der Select Liste müssen im Group By genannt werden.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:26 Uhr.
Seite 1 von 2  1 2      

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