У меня есть таблица прайс-листа в SQL Server 2008R2 и вы хотите рассчитать цену за услугу в зависимости от времени, когда Служба была создана.Расчет времени в прейскуранте
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
Этот ценник показывает разные цены в ночное время, начиная с 19:00 и продлится до 07.00 утра и днем с 07:00 до 19:00.
Минуты должны быть округлены до четверти часа. Есть еще кое-что, о чем можно подумать, например, о минимальном уведомлении Periode (@Vorlaufzeit) и о будни Weekend. Оба условия выполнены, а не проблема. Моя проблема - это первая и последняя запись, в которой я должен округлить и/или закруглить, что неверно. Обе строки имеют 1 в цикле и должны быть скорректированы правильно в обоих обновлениях, но это не так.
Так, например, служба от 2016-11-04 10:50 (округление до 10:45, что составляет 0,25 часа) до 2016-11-04 19:25 (округляется до 19:30, что составляет 0,5 часов) составляет 0,25 + 8 + 0,5 = 8,75 часа и стоит 8,25 * 15 + 0,5 * 20 = 133,75.
Я пробовал с этим кодом, но это не приносит мне правильный результат. Это только первая и последняя запись, где я должен округлить вверх или вниз. Это верно, когда есть полные часы.
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
благодарит за помощью! Майкл
Почему вы используете 'datetime' вместо' time'? –
@PanagiotisKanavos Проделав аналогичные вещи, неспособность «времени» выражать 24 часа (или больше) делает диапазоны, которые пересекают полуночи, что-то вроде кошмара для обработки. Проверка для параметра RangeStart <= Target <= RangeEnd' становится чем-то вроде '(RangeStart <= Target и Target <= RangeEnd) или (RangeStart> RangeEnd и (RangeStart <= Target или Target <= RangeEnd))'. Не так уж плохо, если проверять и скрывать в UDF, но неуклюжие и подверженные ошибкам при рассеянии. – HABO
@HABO нет в этом случае. Это всего несколько часов в день. Однако здесь есть гораздо худшие проблемы, в том числе попытка петли вместо написания правильного запроса –