Anmelden

View Full Version : SQL kleinste Satz



dibe
01-10-24, 13:40
Guten Tag.
ich verzweifel hier an einem SQL

ich haben

Datei 1
FF1, FF2, FF3, FJJ, FMM, FTT, FNR nicht unique

Datei 2
F1, F2, F3, JJ, MM, TT, NR unique

Ich brauche aus Datei 1 die Sätze die die kleinste FJJ, FMM, ,FTT, FNR haben
Dazu verknüpfe ich mit Datei 2, alle 7 Felder 1:1 um eine Bedingung aus der 2. Datei abzufragen

es gibt in Datei1 (Bsp)
1, 1, 1, 2018, 05, 15, 77
1, 1, 1, 2018, 05, 15, 67 <-
1, 1, 1, 2018, 05, 15, 78
1, 1, 1, 2018, 05, 17, 11
irgendwo habe ich eine Fehler

wenn ich mit min(FJJ*10000+FMM*100+FTT) arbeite bekomme ich 2018 05 15
aber bei min(FNR) bekomme ich 11 statt 67

die Guppierung ist iin meinem Kopf kaputt
Hat einer eine Schnelle idee?

Danke
DiBe

Fuerchau
01-10-24, 14:00
Da ich deinen SQL nicht sehe, solltest du den Group By prüfen, wenn du denn überhaupt einen hast.

select FF1, FF2, FF3, FJJ, FMM, FTT, min(FNR)
from myfile
group by FF1, FF2, FF3, FJJ, FMM, FTT

Ein Aggregat wird über den gesammten Gruppenschlüssel gebildet.
Wird kein Group By angegeben, erfolgt das Aggregat über Alles.

dibe
01-10-24, 14:26
Das suchte ich ..


with a as (
select FF1, ff2, ff3,
min(fjj*10000+fmm*100+ftt) as mi
from datei1
where (ff1, ff2, ff3) in(
select f1, f2, f3
from datei2
where hdkz = 10 )
group by f1, f2, f3),
b as (select ff1, ff2, ff3,
min(fjj), min(fmm), min(ftt), min(fnr) as fnr
from datei1 where
(ff1, ff2, ff3,
fjj*10000+fmm*100+ftt) in(
select ff1, ff2, ff3, mi from a)
group by ff1, ff2, ff3)
select * from b

Fuerchau
01-10-24, 15:25
Hinweis:
Einen "where in " kann man mit "where exists " erheblich beschleunigen, da ja die Gruppe selber keine Rolle spielt sondern nur das Vorkommen der Schlüssel.

Der b-Select fasst nur die Gruppe nach ff1, ff2, ff3 zusammen und sucht einzeln das jeweils kleinste fjj, fmm, ftt sowie fnr, die dadurch nicht mehr in Beziehung zueinander stehen.

Zu deinem (angepassten) Beispiel:

1, 1, 1, 2016, 04, 25, 77
1, 1, 1, 2017, 03, 15, 67
1, 1, 1, 2018, 02, 18, 78
1, 1, 1, 2019, 01, 30, 11

Bekommst du die Gruppe mit
1, 1, 1, 2016, 01, 15, 11

Pauschal kannst du auch per

min(digits(ff1) concat digits(ff2) concat digits(ff3) concat concat digits(fjj) concat digits(fmm) concat digits(ftt) concat digits(fnr))

den kleinsten Begriff über alles erhalten oder, wenn die 1. 3 Schlüssel relevant sind:

select ff1, ff2, ff3
, min(digits(fjj) concat digits(fmm) concat digits(ftt) concat digits(fnr))
from datei1
where exists (
)
group by ff1, ff2, ff3

dibe
01-10-24, 16:22
Zu deinem (angepassten) Beispiel:

1, 1, 1, 2016, 04, 25, 77
1, 1, 1, 2017, 03, 15, 67
1, 1, 1, 2018, 02, 18, 78
1, 1, 1, 2019, 01, 30, 11

Bekommst du die Gruppe mit
1, 1, 1, 2016, 01, 15, 11

Das glaube ich nicht. Du hast sicher übersehen das in der b selektion
auch das drin ist:
<code><code>where (ff1, ff2, ff3,
fjj*10000+fmm*100+ftt) in(
select ff1, ff2, ff3, mi from a)

mi ist das min(FJJ*10000+FMM*100+FTT) aus der a selektion

Dadurch habe ich in a nur noch 1, 1, 1, 2016, 04, 25, 77
und ermittel in b nun die 77

(es könnte ja einen 1, 1, 1, 2016, 04, 25, 13 Satz geben, dann würde ich hier die 13 ermitteln)

Oder nicht??

where (feld1, feld2) in(select ...) ist langsamer als
where exists(select * from file where Feld1 = feld1 and feld2 = feld2)??



Danke
DiBe
</code></code>

Fuerchau
01-10-24, 17:07
Zu letzter Frage:
Ja, da der "In" alle Daten durchsuchen muss, da auch der letzte Datensatz die Bedingung erfüllen könnte.
Vor allem dann, wenn er nicht zusätzlich durch einen indizierten Where eingeschränkt wird.
Gibt es aber einen Schlüssel für die Where-Klausel des "[not] exists" ist das genau 1 Zugriff.

Den exists gibts halt noch nicht so lange wie den in, so ca. erst 20 Jahre;-).

<code><code>with a as (
select FF1, ff2, ff3,
min(fjj*10000+fmm*100+ftt) as mi
from datei1
where (ff1, ff2, ff3) in(
select f1, f2, f3
from datei2
where hdkz = 10 )
group by f1, f2, f3),

b as (select ff1, ff2, ff3,
min(fjj), min(fmm), min(ftt), min(fnr) as fnr
from datei1 where
(ff1, ff2, ff3,
fjj*10000+fmm*100+ftt) in(
select ff1, ff2, ff3, mi from a)
group by ff1, ff2, ff3)
select * from b

Deine Einschränkungen der Where-Klauseln ändern daran nun auch nichts.
</code></code>

dibe
02-10-24, 07:38
Danke,
du meinst, das der select min(
ERST den absoluten MIN Wert ermittelt und dann nachsieht ob die Bedingung erfüllt ist?
Und wenn nicht den Satz dann verwirft?

m.e. muß er doch erst die Sätze auswählen die der Bedingung entsprechen und aus dieser Teilmenge das Ergebnis bilden!

Fuerchau
02-10-24, 10:13
So arbeitet SQL nicht.
SQL erstellt keine temporären Zwischenergebnisse, sondern je Zeile werden alle Verbindungen und Berechnungen durchgeführt.

D.h., die Whereklausel für den Subselect auf a wird vor der Gruppierung und der Berechnung von Aggregaten durchgeführt:

1. Select inkl. aller Joins
2. Where-Klausel je Zeile aus 1.
3. Group By mit Aggregatbildung
4. Having Klausel (where auf Gruppenergebnsse)

Da du ja wahrscheinlich mehr Daten hast, als dein Beispiel oben aufzeigt, kann es trotz der Where-Klausel auf a zu mehreren Zeilen der Gruppe FF1-FF3 kommen.

Daher solltest du

<code><code>min(fjj), min(fmm), min(ftt), min(fnr) as fnr

durch

</code></code><code><code>min(fjj*10000+fmm*100+ftt) as mi

ersetzen.
Un die FNR dann zu erhalten kannst du den Extrakt via mod(mi, 100) erhalten.

Select b.*, mod(mi, 100) fnr
from b</code></code>