Zwei Tabellen zusammenführen / Ist Cross Join die beste Lösung?

IchHH

Datenbank-Guru
Beiträge
282
Hallo ich scheitere gerade grandios an ein Problem wo ich echt nicht weiter weiß.

Ich habe eine Tabelle in der es vier Spalten gibt

1. in einer Spalte Kalenderwochen mit Jahr (z.B. 262022, 282022, 292022, 342022)
2. Werte die einen Eingang von Litern darstellen
3. Werte aktuell z.B. 100
4. die Materialnummer

Nun möchte ich aber auch die KW (242022, 252022, 272022, 282022, 292022, 302022 usw.) angezeigt bekommen. Also alle Werte die zwischen den Vorhanden Werten liegen und die Zukunft betreffen.

Mittels Cross Join wollte ich diese mittels einer Kalendertabelle realisieren. Dabei habe ich aber das Problem dass er mit jeder Kalenderwoche anzeigt und dass leider auch mit allen Werte und Materialkombination.

Wie wäre aber hier die richtige Herangehensweise? Mittels FIRST_VALUE habe ich erst gedacht, nur dann würde ich NULL Werte benötigen.
 
Werbung:
Ich schätze, es werden einfach die fehlenden KW Daten (KWYYYY) benötigt, für die noch keine Werte erfasst wurden. Bspw. um eine zeitsynchrone Darstellung in Abfragen zu erhalten.
Die Kalendertabelle wäre da schon genau richtig (es gibt viele Varianten davon). Die muss man einfach left outer mit der Datentabelle joinen. Das ist alles. Man erhält dann zu jeder KW aus der Kalendertabelle, die vorhandenen Daten oder halt null Werte, wenn noch keine Daten zu der KW vorhanden sind.
Anstelle der Kalender Tabelle kann man auch eine virtuelle Tabelle oder so nehmen, die nur im Moment der Abfrage genutzt wird.
Oft wird aber der Bedarf an diesen Vorgabewerten immer größer. Berücksichtige Urlaubstage, Betriebsferien, .. und dann bekommt man über kurz oder lang eine immer breitere oder längere Kalendertabelle.
 
Hallo Thallius & dabadepdu,

es ist so wie es dabadepdu gesagt hat. Ich wollte um eine Zeitreihenanalyse zu machen alle nicht vorhanden KW´s.

ABER: Ein LEFT OUTER JOIN funktioniert nicht. Gleiches gilt für RIGHT OUTER JOIN.

Hier mein aktueller Code.

SELECT * FROM
[dbo].[v_LB_Wareneingaenge_KW]

LEFT OUTER JOIN
(SELECT DISTINCT TheISOweek, TheISOYear FROM [dbo].[DateDimension]) DateDimension

ON [v_LB_Wareneingaenge_KW].KEYDATE = CONCAT([DateDimension].TheISOweek,[DateDimension].TheISOYear)


Ich bekomme keine Werte der Kalendertabelle angezeigt. KeyDate liegt im übrigen auch im Format KWYYYY vor.
 
Sorry mein Fehler. Ich habe da etwas übersehen gehabt. Nun ist doch alles gut. Damit hätte ich die Frage überhaupt nicht stellen müssen. Dennoch danke für eure Unterstützung.
 
Das Grundproblem gibt es ja immer wieder mal. Neben einer Datumstabelle mit allen Werten (oder fehlenden Werten) kann man es auch noch anders lösen. In einigen SQLs gibt es generate_series() als Funktion oder man macht es mit CTE grade zu Fuß. Bei Kalenderwoche ist das gar kein Problem mit Rekursion:
Code:
WITH t AS (
    SELECT    datepart(year,getdate()) AS jahr,
            1 AS kw
    UNION ALL
    SELECT    t.jahr,
            t.kw + 1
    FROM    t
    WHERE    t.kw  + 1 <= datepart(week,dateadd(day,-1,dateadd(year,datediff(year,0,getdate())+1,0)))
    )
SELECT    right('0' + convert(VARCHAR(6),t.kw) + convert(VARCHAR(6),t.jahr),6)
FROM    t
t nimmt man als Basistabelle und darauf joint man dann alle bestehenden Daten.
 
Ok, soweit verstanden. Was mir aber durch das Join mit der Datumstabelle (egal ob eine existente genutzt wird der die "t" gejoint wird) bewußt wird, ist das ich sogar noch zu kurz gedacht habe. Denn durch ein Join mit einer Tabelle werden zwar die fehlenden KW´s hinzugefügt, dafür fehlen mir dann aber z.B. die Materialnummer die ebenfalls mit den fehlenden KW´s eingetragen werden müssten. Das heißt doch ich muss mir eine Datumstabelle mit Materialnummer bauen, die ich kann mit Right Join Verbinde, oder sehe ich das Falsch?
 
wenn ich dich richtig verstehe, wäre die prinzipielle Lösung für Dein Problem, mit den Mitteln von PG, in etwa so:

Code:
postgres=# select * from ichhh ;
 kw | material 
----+----------
 10 |      333
 10 |      444
 12 |      222
 14 |      333
(4 rows)

postgres=#

Du hast also eine KW-Spalte mit Lücken, und in manchen KW's unterschiedliche Materiealien. Du willst nun alle fehlenden KW-Werte ergänzen, zusammen mit allen (bisher verwendeten) Materialien:

Code:
postgres=# begin;
BEGIN
postgres=*# with m as (select distinct material from ichhh), kw as (select * from generate_series((select min(kw) from ichhh),(select max(kw) from ichhh )) except select distinct kw from ichhh) insert into ichhh select * from kw cross join m;
INSERT 0 6
postgres=*# select * from ichhh ;
 kw | material 
----+----------
 10 |      333
 10 |      444
 12 |      222
 14 |      333
 11 |      333
 11 |      444
 11 |      222
 13 |      333
 13 |      444
 13 |      222
(10 rows)

postgres=*#
 
Ok, soweit verstanden. Was mir aber durch das Join mit der Datumstabelle (egal ob eine existente genutzt wird der die "t" gejoint wird) bewußt wird, ist das ich sogar noch zu kurz gedacht habe. Denn durch ein Join mit einer Tabelle werden zwar die fehlenden KW´s hinzugefügt, dafür fehlen mir dann aber z.B. die Materialnummer die ebenfalls mit den fehlenden KW´s eingetragen werden müssten. Das heißt doch ich muss mir eine Datumstabelle mit Materialnummer bauen, die ich kann mit Right Join Verbinde, oder sehe ich das Falsch?
Da wäre es dann tatsächlich sinnvoll einen Cross Join zwischen Datumswerten und qualifizierten Materialnummern zu machen, kann natürlich sehr schnell sehr viel werden. Du willst aber vermutlich keine nicht existenten Materialnummern haben also kannst du auch einfach ein SELECT DISTINCT Materialnummer FROM tabelle mit CROSS JOIN verbinden.
 
Alternativ kann man auch einfach das „auffüllen“ in den applikationslevel stecken. Ist in manchen Fällen wesentlich effektiver
 
Ich würde keine kombinierte, vorbefüllte Tabelle für KW und Materialnummer erstellen / pflegen.
Eine für KW, eine separate für Materialnummer, mglw. nicht jede Materialnummer, nur nach Bedarf, Aktualität. Hier kann man viel "spielen", einbauen, Komfort schaffen.
zu planende KW (je Jahr/ Geschäftsjahr / ..) cross joinen mit gepflegter Materialvorauswahl und man hat was man braucht oder mehr.

Denkbar ist für die Materialliste ein Aktivitätsflag, auf das beim Crossjoin gefiltert wird, auch Warengruppen oder Datumswerte für Gültigkeitsbereiche. Die Liste könnte mit letzteren asynchron gepflegt werden. Aktivität tritt dann per Stichtag ein oder fällt automatisch wieder weg.
 
Ja, ist aber auch weniger dynamisch. Nicht vorprogrammierte Wünsche bedeuten ein Update für Anwendung.
ach, und nicht programmierte Wünsche in der dB brauchen keine update in der dB? Ob ich nun die dB update oder die Applikation das macht ja wohl kaum einen Unterschied. Ich brauche mindestens einen Entwickler und das ganze QM und Deployment Team.
 
Ich habe mich für die Variante von ukulele und dabedepdu entschieden und es läuft super. Allerdings gibt es dadurch ein Problem welches ich ebenfalls nicht Vorausgesehen habe. Ich habe nun alle KW´s brauche aber wenn der Wert NULL ist den Wert der Vorspalte, dass klappt jedoch nicht auf eine Kumulierte Spalte wenn ich da mit Windowfunktion gearbeitet habe und leider ist bei SQL Server die Funktion IGNORE NULL nicht verfügbar. Wie geht man damit um?

Hier der Code den ich für die Kumulierte Spalte nutze

,SUM(WE.MENGE_WE)
OVER (PARTITION BY WE.[EMATN] ORDER BY WE.WERKS,WE.[KW],TheISOYear) Kumulierte_Menge

und so müsste es meines Erachtens aussehen

,SUM(WE.MENGE_WE)
IGNORE NULLS OVER (PARTITION BY WE.[EMATN] ORDER BY WE.WERKS,WE.[KW],TheISOYear) Kumulierte_Menge

Gibt es ein pondon dafür auf SQL Ebene?
 
Werbung:
Ich habe es so versucht

SELECT t.*, max(Kumulierte_Menge) OVER (PARTITION BY [EMATN] ORDER BY WERKS,[TheISOweek],TheISOYear) as new_Value
(
.
.
,COUNT(WE.MENGE_WE) OVER (PARTITION BY WE.[EMATN] ORDER BY WE.WERKS,WE.[KW],TheISOYear) as grp
.
.
.
) t

Dabei ergibt sich aber das Problem das er es in der selben KW für alle Jahre macht und nicht nur da wo er die Werte gefunden hat.
 
Zurück
Oben