Entwickler-Ecke

Datenbanken - "dynamische" SQL-Tabelle?


D. Annies - So 22.07.07 20:29
Titel: "dynamische" SQL-Tabelle?
Hi, Delpher,

Es gibt, sagen wir vier personen (mit verschiedenen Namen) die mehrere, auch verschiedene Artikel geliehen haben.

Gibt es die Möglichkeit, das in einer SQL-Tabelle durch einen SQL-Befehl darzustellen?

Beispiel:

name.dbf
Meier
Müller
Peters
Schulz

artikel.dbf
Boot
Lampe
Säge
Hammer
Zange


gewünschtes Ausgabeergebnis

Name Artikel_01 Artikel_02 Artikel_03 Artikel_04

Meier Boot Lampe Säge Hammer
Müller Lampe Hammer Zange
Schulz Boot Säge Hammer

Versuch 1:

Select * from name.dbf n artikel.dbf a
where (n.name = a.name) order by ...

Also, gewünscht ist, dass die verschiedenen Artikel nebeneinander stehen, man weiß also zunächst nicht, wie viele Spalten die Ergebnistabelle hat!

Vielen Dank für Hilfe
Detlef


mkinzler - So 22.07.07 20:38

Durch ein einfaches Statement nicht, da ja die Spaltenanzahl, wie schon erkannt flexibel ist. Eine Möglichkeit wäre es die Artikel in einer Spalte mit Trennzeichen zu bringen.


D. Annies - So 22.07.07 21:01

Hi, Markus,

könnte ich festlegen, dass die Ergebnistabelle 25 Spalten hat, weil ich weiß, dass jemand sicher - nicht mehr als 25 Artikel haben kann?

Gruß, Detlef


mkinzler - So 22.07.07 21:05

Dann würde es trotzdem Probleme mit dBase geben, da hier keine Limitierung möglich ist. Ich würde eine Normale (Join-)Abfrage nehmen und die Ergennisse erst bei der Anzeige zu drehen.


D. Annies - So 22.07.07 21:14

Hi, Markus,

kannst du mir dabei (auf die Sprüge) helfen?
8) :arrow: :idea: :D

Detlef


mkinzler - So 22.07.07 21:19

Poste mal die fehlende Tabelle, welche die Zuordnung festlegt.


Fabian W. - So 22.07.07 21:29

Mach das doch so:
Du nimmst eine Tabelle für die Leute die etwas ausleihen (ID, Name) und eine Tabelle für die Gegenstände, die die Leute geliehen haben (Kunde_ID, Gegenstand).
Die Abfrage geht dann so: select balbla... where Kunde_ID = ID

mfg


D. Annies - So 22.07.07 21:40

Hi, Markus,

die fehlende Tabelle hat den Aufbau:

Artikel Name Leihdatum

Hammer Meier 05.07.2007
Hammer Müller 06.07.2007
Säge Meier 03.07.2007

usw., (als Beispiel)

Detlef


mkinzler - So 22.07.07 21:49

Ich würde die Klartextbezeichnungen der Ausleihe durch echte Fremschlüssel ersetzen:
name.dbf
ID Name
1 Meier
2 Müller
3 Peters
4 Schulz

artikel.dbf
ID Bez
1 Boot
2 Lampe
3 Säge
4 Hammer
5 Zange

ausleihe.dbf
Artikel Name Leihdatum
4 1 05.07.2007

4 2 06.07.2007
3 1 03.07.2007


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
id:=0;
Query.SQL.Text := 'select a.bez, n.id as nid, n.name, l.leihdatum from ausleihe l join name n join n.id = l.name and artikel a on a.id = l.artikel order by l.name';
Query.Open;
while not Query.EOF do
begin
    if Query1.FieldByName('nid').Value <> id then //Neue Zeile
...
end;


D. Annies - So 22.07.07 22:18

Hi, Markus,

erstmal danke für deine Antwort!

Das "Drehen" habe ich noch nicht verstanden.

Detlef


mkinzler - So 22.07.07 22:20

Solange sich die Id des Ausleihers nicht ändert wird ein neue Spalte erzeugt, sonst neue Zeile.

Hammer 1 Meier 05.07.2007
Säge 1 Meier 03.07.2007
Hammer 2 Müller 06.07.2007

=>

Meier Hammer Säge
Müller Hammer


D. Annies - So 22.07.07 22:24

Aha!

Dann werd ich mal ... :P

Detlef


D. Annies - So 22.07.07 22:34

Sorry, Markus, ich habe etwas (wichtiges) übersehen:

Name.dbf

Meier Lübeck
Müller Hamburg
Peters Lübeck
Schulz Lübeck

Die Auswertung soll nach dem Ort erfolgen! (!)

Leihtabelle also:

Artikel Name Leihdatum Ort
.. .

Detlef :oops:


Blawen - Mo 23.07.07 00:48

user profile iconD. Annies hat folgendes geschrieben:
Sorry, Markus, ich habe etwas (wichtiges) übersehen:

Name.dbf

Meier Lübeck
Müller Hamburg
Peters Lübeck
Schulz Lübeck

Die Auswertung soll nach dem Ort erfolgen! (!)

Leihtabelle also:

Artikel Name Leihdatum Ort
.. .

Detlef :oops:
Was spricht dagegen, die Tabelle zu erweitern und entsprechend sortieren zu lassen?

ID Name Wohnort
1 Meier Lübeck
2 Müller Hamburg
3 Peters Lübeck
4 Schulz Lübeck

Delphi-Quelltext
1:
...order by l.Ort                    

Selbstverständlich kannst Du auch kombinieren.


D. Annies - Mo 23.07.07 11:09

Hi, Markus und Blawen,

1. kann es sein, dass der SQL-Befehl falsch ist?
... join name n join n.id = l.name ...

2. wie "geht" denn nun die neue Zeile?
... then // neue Zeile


Danke für weitere Unterstützung,
Detlef


Blawen - Mo 23.07.07 22:12

Ich habe ehrlich gesagt im Moment nicht den Überblick über Deine effektive DB-Struktur und Mutmassungen liebe ich nicht. Daher poste ich mal ein einfaches und universelles Beispiel:


SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
Select * From MITARBEITER
INNER JOIN (KONTAKTDATEN,PLZ,LAENDER,ABTEILUNG) 
ON MITARBEITER.KONTAKTDATEN_ID = KONTAKTDATEN.KONTAKTDATEN_ID AND 
MITARBEITER.PERSONALNUMMER Like "' + Edit_Suche.Text + '%" AND
KONTAKTDATEN.PLZ_ID = PLZ.PLZ_ID AND 
KONTAKTDATEN.ABTEILUNG_ID = ABTEILUNG.ABTEILUNG_ID AND
PLZ.LAENDER_ID = LAENDER.LAND_ID
ORDER by KONTAKTDATEN.Nachname DESC, KONTAKTDATEN.VORNAME DESC


Hier existieren 4 Tabellen
- Mitarbeiter (spez. MA-Daten)
- Kontaktdaten (Sammel-DB für alle "Kontakte" - inkl. MA)
- PLZ (Postleitzahlen und entsprechende Ortschaften)
- Land (Länderverzeichnis)

Ausgegeben werden sollen diejenigen Datensätze der MA, bei welchen die Personalnummer mit den gleichen Zeichen beginnen, welche im Edit-Feld stehen.

Moderiert von user profile iconUGrohne: Delphi- durch SQL-Tags ersetzt


D. Annies - Di 24.07.07 11:36

Hi, Blawen (&Markus)

danke für deine Mühe, das ist alles so korrekt, ich bekomme die gewünschten Daten, aber wie bekomme ich sie nebeneinander statt untereinander? - Oder geht das nicht? :cry:

Gruß, Detlef


mkinzler - Di 24.07.07 19:45

In der Abfrage nicht, du kannst dies aber wie oben schon mal skizziert bei der Anzeige machen.


Blawen - Di 24.07.07 23:57

user profile iconmkinzler hat folgendes geschrieben:
In der Abfrage nicht, du kannst dies aber wie oben schon mal skizziert bei der Anzeige machen.
Oder anders ausgedrückt:
Liste durchgehen und manuell in einem StringGrid eintragen:

- Gleicher Kunde -> Eintrag in neuer Spalte
- Neuer Kunde -> Neue Zeile beginnen


alzaimar - Mi 25.07.07 08:36

Um die Artikel nebeneinander zu bekommen, bietet sich eine Pivot-Tabelle (Crosstab) an. Dazu sollten die einzelnen Artikel je Name/Ort durchnumeriert werden. Alle Artikel mit gleichen Sequenznummer kommen dann in die selbe Spalte.

Das kann man in SQL lösen, aber ich finde das keine besonders gute Idee, da man das notwendige SQL-Kommando zur Laufzeit erstellen muss. Als Übung wäre es allerdings ein guter Brainteaser. Wenn es sich allerdings um sehr viele Daten handelt, kann eine Lösung in SQL performanter sein, da das notwendige Datenschaufeln im Server stattfindet.

Beispiel;

Nehmen wir an, Du möchtest eine Tabelle der Form

Name | Artikel_0 | Artikel_1 | ..... | Artikel_N

Wir benötigen eine temporäre Tabelle (=ZwischenResultat) der Form (Name, Artikel, ArtikelSeqNr). Die ArtikelSeqNr beginnt für jeden Namen bei 0 und ordnet die Artikel je Namen. Zunächst musst Du die höchste Artikelsequenznummer ermitteln. Das ergibt die Anzahl der Artikelspalten (Nennen wir diesen Wert 'N').
Anschließend bastelst Du dir das SQL-Kommando in etwa so zusammen (im Einzelnen ist es abhängig vom SQL-Dialekt):

SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
select Name,
       (case when ArtikelSeqNr = 0 then Artikel else null endas Artikel_0,
       (case when ArtikelSeqNr = 1 then Artikel else null endas Artikel_1,
...
       (case when ArtikelSeqNr = N then Artikel else null endas Artikel_N
from  ZwischenResultat
group by Name


Bleibt nun noch das Problem, wie man das Zwischenresultat erstellt. Dazu müssen wir eine totale Ordnung auf den Artikeln aufbauen. Entweder alphabetisch, oder wir nehmen einfach die ID der von MKinzler vorgeschlagenen Artikel-Tabelle. Die Artikelsequenznummer wäre dann die Anzahl der Artikel eines Namens, deren ID kleiner ist, als die ID des Artikel selbst. Hu? Klingt kompliziert, ist es aber nicht.

Ich habe mir erlaubt, die Feldbezeichner der Tabelle 'Ausleihe' etwas zu ändern: Name=>NameID und Artikel=>ArtikelID


SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
select Name.Name,
       Artikel.Artikel,
       (select count (*) 
          from Ausleihe X 
         where X.NameID = Name.ID 
               and X.ArtikelID < Artikel.ID
       ) as ArtikelSeqNr
from   Name
       Join Ausleihe on Name.ID = Ausleihe.NameID
       Join Artikel on Artikel.ID = Ausleihe.ArtikelID


(Ungetestet und aus dem Kopf runtergerasselt)

Blöderweise arbeitest Du mit DBase, sodaß es sein kann, das Du das wirklich so nicht geht und Du -wie Blawen meint- ein Stringgrid bastelt must. Als Denkanstoß und Proof-Of-Concept sollte mein Ansatz aber schon reichen.


D. Annies - Mi 25.07.07 09:50

Hi, Delpher-Helfer!

Ihr drei seid ja ordentlich am Ackern, vielen Dank bisher.
Die Anregungen werde ich jetzt verarbeiten und anpassen.
Komisch, dass dazu auch im Netz so gut wie nichts steht; es ist doch technisch gesehen nichts anderes als ein (einstufiger!) Gruppenwechsel!! - und da interessiert mich eine SQL-Lösung etwas mehr als eine Stringgrid-Lösung. Aber wenn das zu schwierig sein sollte, muss ich es lassen - aber erstmal beißen ...

Danke und Gruß,
Detlef
P.S. wenn euch noch was einfällt ...


D. Annies - Do 26.07.07 22:37

Wollte mich nur mal melden! Bin noch dabei.

Danke, melde mich wieder,
Detlef


D. Annies - So 29.07.07 19:54

Hi,

ich werde es mit einem Stringgrid machen ... :cry: ... müssen, ich kriege es anders nicht gebacken. - Man muss auch seine - oder die SQL- Grenzen erkennen.

Danke für eure Ideen,
Detlef