SQL Zeitraum ist gegeben und ausgegeben werden soll das Datum

aviQ

Newbie
Registriert
Dez. 2015
Beiträge
5
Hallo,

ich habe folgendes Problem:
Ich habe in der Datenbank die Spalten Datumvon und Datumbis, die für mich relevant sind. Ich möchte, dass alle weiteren Infos nicht in dem Zeitraum (Datumvon, Datumbis), sondern für jedes einzelne Datum ausgegeben wird. So soll es sein:

Datum-----------Tätigkeit-----statt---Datumvon-----Datumbis----Tätigkeit
01.01.2016-----Maler-----------------01.01.2016---04.01.2016-Maler
02.01.2016-----Maler
03.01.2016-----Maler
04.01.2016-----Maler

Ist solch eine Trennung überhaupt SQL-technisch möglich? Wenn ja, kann mir da vielleicht wer weiterhelfen?
Die Abfrage für die Ausgabe in dem Zeitraum könnte ja beispielsweise so aussehen:
Select Tätigkeit from Einsatz where Datumvon >= 01.01.2016 AND Datumbis <= 04.01.2016
 
So ganz verstehe ich dein Anliegen nicht. Ist die von dir dargestellte "Tabelle" der IST oder der SOLL Stand?
Sind die Spalten mit Daten korrekt vom Datentyp "date/datetime"?

Kannst du mal bitte den IST-Stand deiner Tabelle zeigen und was ausgegeben werden soll.
 
Ok, das habe ich vielleicht nicht eindeutig dargestellt, sorry^^ Datentyp ist date, jupp.

IST-Zustand

Tätigkeit Datumvon Datumbis
Maler 01.01.2016 04.01.2016

SOLL-Zustand

Tätigkeit Datum
Maler 01.01.2016
Maler 02.01.2016
Maler 03.01.2016
Maler 04.01.2016
 
Denke nicht, daß das ohne Programm möglich ist, denn Du brauchst ja eine Iteration über ein Tag.
 
Könnte mir vorstellen das es mit einer Stored Procedure geht, wo ein Zeiger über JEDES Datum eines Jahres läuft und schaut ob der Tag in den Datensätzen vorhanden ist. Falls ja wird es in eine Tabelle eingetragen, falls nein eben nicht.
Das wäre aber wirklich rechenaufwändig...
was besseres fällt mir aber nicht ein.
 
Oder es befände sich eine Tabelle mit "Kalender", z.B. Arbeitstage, im System. Dann könnte es über einen Join gehen.
 
Ich hab mir auch gedacht, dass wenn sowas überhaupt möglich ist, nur über eine sehr komplexe Prozedur zu schaffen ist, in der eine Schleife eingebaut ist. Da ich selbst aber noch nicht wirklich viel mit Prozeduren gearbeitet habe, hatte ich auf Hilfe gehofft :D Kann sich denn jemand eine konkrete Lösung vorstellen? Wenn ja, wie könnte Sie aussehen?
 
Ich finde die Ursprungsdatenbank etwas unvorteilhaft gestaltet.

Tabelle: Beruf
ID______Taetigkeit
1 ______Maler

Tabelle: Einsatz
ID_____Taetigkeit_ID_____Datum_ID
1_____ 1_________________1

Tabelle: Datum
ID_____Datum
1______01.01.2016


Select * from "Datum"
join "Einsatz"
on "Datum"."ID"="Einsatz"."Datum_ID"
join "Beruf"
on "Beruf"."ID"="Einsatz"."Taetigkeit_ID"
where "Taetigkeit"=1;
 
Ich habe hier eine Funktion erstellt, die dir die Tage zwischen zwei definierten Daten ermittelt und ausgibt. Du kannst dann ganz einfach mit dieser Funktion joinen und hast dein erwartetes Ergebnis.


Funktion :
Code:
CREATE FUNCTION [dbo].[ListDatesBetween](@DateFrom date, @DateTo date)
RETURNS @return TABLE 
(
    ActionDate date
)
AS 
BEGIN
	DECLARE @COUNTER int = 0

	WHILE @COUNTER <= DATEDIFF(DAY, @DateFrom, @DateTo)
	BEGIN
		INSERT INTO @return SELECT DATEADD(DAY, @COUNTER, @DateFrom)
		SET @COUNTER = @COUNTER + 1
	END
    RETURN
END

Abfrage :
Code:
SELECT X.Activity, Y.ActionDate
FROM @ttest AS X
CROSS APPLY dbo.ListDatesBetween(X.DateFrom, X.DateTo) AS Y
 
Vielen Dank, ich teste das direkt mal aus! :)
Ergänzung ()

Ich habe Probleme dabei es ins Firebird zu übertragen. Verstanden habe ich es aber schon. Ich werde euch aufm Laufenden halten, wenn ich es geschafft hab, kann aber dauern, weil ich mich noch ein wenig firebirdbezüglich belesen muss :D
 
Du kannst es ad-hoc auch mit einem Cursor machen, dann musst du keine Objekte wie Functions oder Procedures anlegen. Das ganze sieht dann so aus (auf das DB Design geh ich jetzt nicht ein; ich nehme mal das was du angegeben hast):

Code:
CREATE TABLE ArbeitsKalender
(
Datum_von DATE NOT NULL,
Datum_bis DATE NOT NULL,
Taetigkeit VARCHAR(50) NOT NULL
)

INSERT INTO ArbeitsKalender (Datum_von, Datum_bis, Taetigkeit)
VALUES
('20160101','20160104','Maler'),
('20160103','20160107','Tischler')

SELECT * FROM ArbeitsKalender

Dabei kommt raus:

[table="width: 300, class: grid"]
[tr]
[td]Datum_von[/td]
[td]Datum_bis[/td]
[td]Taetigkeit[/td]
[/tr]
[tr]
[td]2016-01-01[/td]
[td]2016-01-04[/td]
[td]Maler[/td]
[/tr]
[tr]
[td]2016-01-03[/td]
[td]2016-01-07[/td]
[td]Tischler[/td]
[/tr]
[/table]

Und jetzt das Query:

Code:
DECLARE @TempTable TABLE (Datum DATE, Taetigkeit VARCHAR(50))
DECLARE @Datum_von DATE
DECLARE @Datum_bis DATE
DECLARE @Taetigkeit VARCHAR(50)
DECLARE @Counter INT = 0
DECLARE MyCur INSENSITIVE CURSOR FOR
SELECT Datum_von, Datum_bis, Taetigkeit FROM ArbeitsKalender
OPEN MyCur
FETCH NEXT FROM MyCur INTO @Datum_von, @Datum_bis, @Taetigkeit
WHILE @@FETCH_STATUS = 0
BEGIN
	SET @Counter = 0
	WHILE @Counter <= DATEDIFF(DAY, @Datum_von, @Datum_bis)
	BEGIN
		INSERT INTO @TempTable SELECT DATEADD(DAY, @COUNTER, @Datum_von), @Taetigkeit
		SET @Counter += 1
	END
	FETCH NEXT FROM MyCur INTO @Datum_von, @Datum_bis, @Taetigkeit
END
CLOSE MyCur
DEALLOCATE MyCur
SELECT * FROM @TempTable ORDER BY Datum

Dann kommt es so raus wie du es willst:

[table="width: 300, class: grid"]
[tr]
[td]Datum[/td]
[td]Taetigkeit[/td]
[/tr]
[tr]
[td]2016-01-01[/td]
[td]Maler[/td]
[/tr]
[tr]
[td]2016-01-02[/td]
[td]Maler[/td]
[/tr]
[tr]
[td]2016-01-03[/td]
[td]Maler[/td]
[/tr]
[tr]
[td]2016-01-03[/td]
[td]Tischler[/td]
[/tr]
[tr]
[td]...[/td]
[td]...[/td]
[/tr]
[/table]
 
Zuletzt bearbeitet:
So... Ich habe nun eine ganze Weile dran gearbeitet, habs aber nach wie vor noch nicht umgesetzt bekommen, da ich das über Firebird zum Laufen bringen muss und es leider etwas anders funktioniert. Vorher habe ich mit einer For-Select-Anfrage gearbeitet, konnte aber wie gesagt den Stichtag nicht mit einbauen. Der Versuch die while-Schleife mit einer For-Select-Anfrage zu koppeln hat nicht funktioniert, da dann die while-Schleife ignoriert wurde... Dann habe ich die For-Select-Anfrage versucht in die while-Schleife zu überführen und das Ergebnis findet ihr hier:

SQL-Statement:

Select * FROM temp([3Von:],[3Bis:])

Die Prozedur:

(
Von DATE
Bis DATE
)
RETURNS
(
PersNr INTEGER,
AuftragNR INTEGER,
NName CHAR(60),
VName CHAR(60),
Datumvon DATE,
Datumbis DATE,
Stichtag DATE,
Bezeichn CHAR(60)
)

AS

DECLARE VARIABLE XPersNr INTEGER;
DECLARE VARIABLE XAuftragNR INTEGER;
DECLARE VARIABLE XNName CHAR(60);
DECLARE VARIABLE XVName CHAR(60);
DECLARE VARIABLE XDatumvon DATE;
DECLARE VARIABLE XDatumbis DATE;
DECLARE VARIABLE XBezeichn CHAR(60);
DECLARE VARIABLE XStichtag DATE;

Begin
i = 0;
while (i <=DATEDIFF(DAY, :Von, :Bis)) DO BEGIN
SELECT Personal.PersonalNr, EinsPers.AuftragNr, Personal.NachName, Personal.Vorname, DATEADD(DAY, :i, :Von) as Stichtag, Einspers.Datumvon, EinsPers.Datumbis, Einspers.Bezeichn
FROM (EinsPers
LEFT JOIN Personal
ON EinsPers.PersonalNr = Personal.PersonalNr)
LEFT JOIN Auftrag
ON Einspers.Auftragnr = Auftrag.Auftragnr
WHERE Personal.PersStatus="2"
AND Einspers.Datumvon <= :Bis
AND Einspers.DatumBis >= :Von
INTO :XPersNr, :XAuftragNR, :XNName, :XVName, :XStichtag, :XDatumvon, :XDatumbis, :XBezeichn;
i = i+1;
END
END

(Die SQL-Abfrage kann Fehler beinhalten, da ich Unwesentliches weggelassen habe)
Ich erhalte folgende Fehlermeldung: multiple rows in singleton select at procedure ‚T_Pramtemp‘

Die while-Schleife möchte mehrere Zeilen auf einmal ausgeben, eine For-Schleife gibt nacheinander eine Zeile aus. An sich denke ich also, dass ich die Fehlermeldung verstehe, nur weiß ich nicht, wie ich diese Problemstellung lösen kann. Gibt „SELECT * FROM temp([3Von:], [3Bis:])“ generell immer nur eine Zeile aus? Wenn ja, wie lässt sich die While-Schleife dann ausführen?
 
Ich möchte dir nochmals die Tabellenmethode ans Herz legen.

Dort kannst Du Wochenenden, Feiertage usw., und über weitere Tabelllen auch Urlaube hinterlegen.

Damit wird dann eine Selektion viel einfacher und solche Tabellen braucht jede Firma.

Du muß diese nur einmal füllen und dann ggfls. manuell pflegen.
 
Bau dir wie miac auch schreibt einfach eine Tabelle mit allen Datümern, die es gibt bzw. die du brauchen wirst (also von mir aus 1.1.2016 bis 31.12.2030). Dann joinest du über den Zeitraum von deiner ursprünglichen Tabelle auf diese und schwupps vervielfältigen sich die Zeilen so wie dus brauchst. Das Ganze sollte zudem sehr performant sein. Also dann z.B.
Code:
Select z.Datum, t.*
from auftrag t
join alleDatümer z
on z.Datum >= t.DatumVon
and z.Datum <= t.DatumBis

Theoretisch würde sich die Menge aller Datümer auch per Rekursivem SQL erzeugen lassen aber das macht eigtl. wenig Sinn, das bei jeder Abfrage dann zu erzeugen.

Man könnte es wohl auch ganz generell über ein rekursives SQL probieren, das ist aber auf jeden Fall inperformanter als mit der ersten Variante. In etwa so (Habs nicht ausprobiert, nur als Denkidee; Ich vermute, dass es noch Duplikate wirft):
Code:
with recursive cte(AuftragNr, NName, VName, Datumvon) as (
    select AuftragNr, NName, VName, Datumvon As Datum
    from auftrag
    union all
    select cte.AuftragNr, cte.NName, cte.VName, cte.Datumvon + 1 Day As Datum
    from cte
    inner join auftrag
    and cte.AuftragNr = auftrag.AuftragNr
    and cte.Datumvon < auftrag.Datumbis
)
select * from cte
 
Zuletzt bearbeitet:

Ähnliche Themen

Zurück
Oben