Ich habe eine Preisliste Tabelle in SQL Server 2008R2 und möchte den Preis für einen Service nach der Zeit berechnen, wo der Service gemacht wurde.Berechnung der Zeit in einer Preisliste
timefrom |timeto |Price
-------- |------ |-----
1900-01-01 00:00:00|1900-01-01 07:00:00|20.00
1900-01-01 07:00:00|1900-01-01 19:00:00|15.00
1900-01-01 19:00:00|1900-01-02 00:00:00|20.00
Diese Preisliste Zeigt verschiedene Preise während der Nachtzeit um 19:00 Uhr beginnt und dauert bis 07.00 Uhr und tagsüber von 7.00 bis 19.00 Uhr.
Minuten müssen auf Viertel Stunden aufgerundet werden. Es gibt noch einige Dinge zu beachten, wie zB Mindestvorlaufzeit (@Vorlaufzeit) und ob Wochentag am Wochenende. Beide Bedingungen sind erfüllt und nicht das Problem. Mein Problem ist der erste und der letzte Datensatz, bei dem ich aufrunden und/oder abrunden muss, was inkorrekt ist. Beide Zeilen haben 1 in der Schleife und sollten in den beiden Updates korrekt korrigiert werden, tun dies aber nicht.
Also zum Beispiel ein Service vom 2016-11-04 10:50 (Abrunden auf 10:45, was 0,25 Stunden ist) bis 2016-11-04 19:25 (aufgerundet auf 19:30, was 0,5 ist Stunden) beträgt 0,25 + 8 + 0,5 = 8,75 Stunden und kostet 8,25 * 15 + 0,5 * 20 = 133,75.
Ich versuchte mit diesem Code, aber es bringt mir nicht das richtige Ergebnis. Es ist nur die erste und die letzte Aufzeichnung, in der ich auf- oder abrunden muss. Es ist nur richtig, wenn es volle Stunden gibt.
DECLARE @Dauer int
DECLARE @X int --Loopcounter für Stunden
declare @Y int --Loopcounter für Tageszahler
declare @Anfangszeit datetime
declare @Anfangsstunde datetime
declare @Endzeit datetime
declare @Vorlaufzeit int --in Minuten
declare @ErsteZeitvon datetime
declare @SummeAnzStunden decimal(8,2)
declare @MinimumZeit int
declare @ZeitvonVolleStunde int -- aus 07:25 mach 7 Uhr
declare @ZeitbisVolleStunde int
declare @AnfangsDatumZeit as datetime
declare @EndDatumZeit as datetime
declare @AnfangsDatumZeitLoop as datetime
declare @AnfangsZeitLoop as datetime
declare @TagesZaehler int
set @AnfangsDatumZeit = @[email protected]
set @EndDatumZeit = @[email protected]
set @Tageszaehler=datediff(day,@AnfangsDatumZeit, @EndDatumZeit)
declare @t1 table (PreisID int, AnzStunden decimal(5,2), Preis decimal(8,2), Anfangszeit datetime, Prüfzeit datetime, startzeit datetime, endezeit datetime, Vorlaufzeit int, Dauer int, PreisFT decimal(8,2), DatZeitvon datetime, DatZeitbis datetime, Tageszaehler int)
-- Insert statements for procedure here
set @ZeitvonVolleStunde=Datediff(hour, '00:00:00', @Zeitvon)
set @ZeitbisVolleStunde=Datediff(minute, '00:00:00', @Zeitbis)
set @Dauer=ceiling(Datediff(minute, @AnfangsDatumZeit, @EndDatumZeit)/60.00)
set @Vorlaufzeit=datediff(minute,@Bestelldatum, @AnfangsDatumZeit)
SET @X = 0
if Datediff(minute, @AnfangsDatumZeit, @EndDatumZeit) > 360
begin
WHILE (@X <[email protected]) --z.b. 13
begin
--set @Y = datediff(day,@AnfangsDatumZeit,@AnfangsDatumZeitLoop)
set @Y = datediff(day,@AnfangsDatumZeit,dateadd(hour,@X, @AnfangsDatumZeit))
set @AnfangsDatumZeitLoop=dateadd(hour,@X, @AnfangsDatumZeit)
set @AnfangsZeitLoop=dateadd(hour,@X, @Zeitvon)
insert into @t1 (PreisID, AnzStunden, Preis , Anfangszeit, Prüfzeit, DatZeitvon , DatZeitbis )
SELECT top 1 preisID, 1, Preis, @AnfangsZeitLoop, @AnfangsDatumZeitLoop, Zeitvon, Zeitbis
FROM dbo.Mypricetable
where [email protected] --SdlID
and Wochentag=case when DATEPART(dw,@AnfangsDatumZeitLoop) < 6 then 'W' else 'S' end --Wochentag
and @Vorlaufzeit BETWEEN Vorlaufzeitvon and Vorlaufzeitbis --Vorlaufzeit in Minuten
AND @Dauer*60 BETWEEN Dauervon AND Dauerbis --DauerInMinuten
and @AnfangsZeitLoop between Zeitvon and Zeitbis --sucht die von/bis Zeitgruppe
order by zeitvon
SET @X = @X + 1
end
--check and udate of the first record in @t1 rounding down to 15 minutes
update @t1 set Anzstunden= Anzstunden + CONVERT(DECIMAL(6, 2), ROUND(((datediff(minute,[dbo].[sfRoundToHourParts](@AnfangsDatumZeit,1), [dbo].[sfRoundToHourParts](@AnfangsDatumZeit,4)) + 7)/60.00)/25, 2) * 25)
from @t1 c where c.Prüfzeit=(SELECT Top 1 Prüfzeit from @t1 order by Prüfzeit)
--check and udate of the last record in @t1 rounding up to 15 minutes
update @t1 set Anzstunden= round(convert(decimal(5,2),datepart(minute,@EndDatumZeit)+7)/60/25,2)*25
from @t1 c where c.Prüfzeit=(SELECT Top 1 Prüfzeit from @t1 order by Prüfzeit DESC)
end
select * from @t1 order by Prüfzeit
Danke Ihre Hilfe! Michael
Warum verwenden Sie 'datetime' anstelle von' time'? –
@PanagiotisKanavos Nachdem man ähnliche Dinge getan hat, macht die Unfähigkeit der "Zeit", 24 Stunden (oder mehr) auszudrücken, Bereiche, die Mitternacht zu einem Alptraum werden lassen. Die Suche nach 'RangeStart <= Target <= RangeEnd' wird zu etwas wie' (RangeStart <= Target und Target <= RangeEnd) oder (RangeStart> RangeEnd und (RangeStart <= Target oder Target <= RangeEnd)) '. Nicht so schlecht, wenn es in einer UDF getestet und versteckt wird, aber ungeschickt und fehleranfällig, wenn es verstreut wird. – HABO
@HABO nicht in diesem Fall. Das sind nur Stunden an einem Tag. Es gibt jedoch weit schlimmere Probleme, einschließlich des Versuches, eine richtige Abfrage zu schreiben, anstatt eine richtige Abfrage zu schreiben –