2016-09-08 5 views
2

Stellen Sie sich vor, ich habe ein Geschäft, das Widgets minutenweise mietet, aber die Mietpreise variieren je nach Wochentag und Tageszeit. Ich beschreibe diese Informationen in einer Tabelle „Preise“ wie folgt:Berechnung Preis basierend auf wechselnden Stundensätzen

CREATE TABLE Rates (
    DayNumber int, 
    HourNumber int, 
    HourlyRate decimal(19,4), 
    PRIMARY KEY (DayNumber, HourNumber) 
) 

DayNumber HourNumber HourlyRate 
--------- ---------- ---------- 
1   1   3.75 
1   2   4.50 
1   3   4.25 
1   4   3.75 

In der obigen Tabelle ist der Tag Zahl von datepart(dw, Start), die Stundenzahl von datepart(hour, Start) abgerufen. Es hat 168 Datensätze (die Anzahl der Stunden in einer Standardwoche).

Ich habe die Mietinformation wie in einem „Mieten“ Tabelle folgt:

CREATE TABLE Rentals (
    RentalId int, 
    CustomerId int, 
    Start datetimeoffset, 
    Finish datetimeoffset, 
    Cost decimal(19,4), 
    PRIMARY KEY (RentalId) 
) 

RentalId CustomerId Start   Finish   Cost 
-------- ---------- --------------- --------------- ---- 
1   1   1/1/2016 6:11am 1/1/2016 2:34pm 
2   1   1/2/2016 7:23am 1/3/2016 8:12am 

Mit T-SQL (SQL Server 2014 oder höher), würde Ich mag Vermietungen Tabelle aktualisieren, die Cost zu berechnen Spalte, die die Rate jeder Tag-Stunde berücksichtigt, summiert für die gesamte Mietdauer. Bonuspunkte für Effizienz.

+1

Gilt die 'HourNumber' für 24HH Format? Angenommen, die Rate von "HourNumber 4" gilt für 4 Uhr morgens, 4 Uhr nachmittags. oder beides? –

+0

Um die Kosten zu berechnen, möchten Sie den Startpreis für die gesamte Mietdauer verwenden oder den Tarif verwenden, der für alle spezifischen Stunden der Mietdauer gilt? – AXMIM

+0

@JoshPart 'datepart (Stunde, Start)' würde "4" für 4 Uhr und "16" für 4 Uhr zurückgeben. –

Antwort

2

Getestet in SSMS, aktualisiert es die Tabelle jetzt. Es löste die folgenden Probleme:

1) es funktioniert, egal ob START und FINISH am selben Tag sind oder nicht;

2) es funktioniert, egal ob START und FINISH in der gleichen Woche oder Monat sind.

update rentals 
set cost = (select sum(hourlyrate) from rates 
       where (daynumber > datepart(dw,start) and daynumber < datepart(dw,finish)) or 
       (daynumber = datepart(dw,start) and hournumber > datepart(hour,start)) or 
       (daynumber = datepart(dw,finish) and hournumber < datepart(hour,finish)) 
       ) + 
       (select hourlyrate from rates 
       where daynumber = datepart(dw,start) and hournumber = datepart(hour,start) 
       ) * 1.00 * (60-datepart(minute, start))/60 + 
       (select hourlyrate from rates 
       where daynumber = datepart(dw,finish) and hournumber = datepart(hour,finish) 
       ) * 1.00 * datepart(minute, finish)/60 - 
       (
        Case when datediff(day,start,finish)%7 = 0 then 230 -- deal with same day case 
         when datediff(day,start,finish)%7 <> 0 then 0 
        end 
       ) + 
       (select datediff(day,start,finish)/7 * sum(hourlyrate) from rates) -- deal with multiple weeks case 
+0

Gute Lösung, Sie müssen jedoch Ihren Zustand beheben, weil es nicht die richtigen Kosten berechnet. Außerdem könnten Sie vereinfachen, nur ein Aggregat zu haben. Ich vermute, dass dies auch die Kostenberechnung fixieren würde. – AXMIM

+0

Auch OP fragte nach einem Update, kein Select. – AXMIM

+0

@AXMIM, danke für den Hinweis, ich aktualisiere meine Antwort, und jetzt funktioniert es und sogar für mehrere Ecken Fälle. –

2

Sie können eine tally table verwenden, um den Datensatz in einen Datensatz pro Stunde aufzuteilen.

Zum Beispiel die folgende Miete

RentalId CustomerId Start   Finish   Cost 
-------- ---------- --------------- --------------- ---- 
1   1   1/1/2016 1:30pm 1/1/2016 4:45pm 

verarbeitet wird tally in

RentalId Start   Finish   Cost 
-------- --------------- --------------- ---- 
1   1/1/2016 1:30pm 1/1/2016 2:00pm 1 
1   1/1/2016 2:00pm 1/1/2016 3:00pm 2 
1   1/1/2016 3:00pm 1/1/2016 4:00pm 3 
1   1/1/2016 4:00pm 1/1/2016 4:45pm 4 

Mit diesem können Sie die Kosten für jede vorverarbeitet Datensätze berechnen. Sie müssen die Rate pro Minute verwenden, da nicht alle Datensätze eine volle Stunde dauerten.

Dann summieren Sie einfach diese Kosten nach Miete gruppiert und Sie haben die Kosten für jede Vermietung.

Hier ist die komplette Lösung.
Ich verwendete CTE für die Tally-Tabelle und vorverarbeitete Datensätze.

Für die Leistung sind sie arm, aber es ist aufgrund Ihrer Datenbank-Design. Ohne, das Design zu ändern, wird es wirklich schwer sein, besser als das, was diese Lösung tut, zu sein. Allerdings würde ich herausfordern, wenn Sie für diese Aufgabe wirklich rockende Leistung benötigen.

Haftungsausschluss: Sie sollten einige Tests vor der Verwendung in der Produktion durchführen, weil ich nicht jeden Rand Fall getestet habe, die es gibt. Möglicherweise haben Sie auch fehlende Raten in Ihrer Preistabelle.

+0

Welche Änderungen würden Sie in der Tabellenstruktur empfehlen, um die Leistung zu verbessern? –

+0

Bevor Änderungen empfohlen werden, wäre es am besten zu wissen, in welchem ​​Kontext dies ausgeführt wird. Zum Beispiel, wie oft und für wie viele Anmietungen jedes Mal berechnet wird. Wenn dies ein One-Shot-Deal ist, würde ich mich nicht mit der Leistung beschäftigen. Ich würde auch nicht, wenn das mit nur ein paar hundert Mieten pro Tag läuft. Ich nehme jedoch zurück, dass meine Lösung schwer zu übertreffen ist. Obwohl es momentan nicht richtig funktioniert, hat Dance-Henrys Lösung das Potenzial, meine zu schlagen. Vor allem auf wirklich lange Miete. – AXMIM

+0

@GeoffArmstrong Mein früherer Umgang mit fehlenden Raten in der Tariftabelle war wirklich falsch. Es war sowieso ein Preis, der wirklich schlecht ist. Bitte beachten Sie meine Bearbeitung, ich habe die fehlende Ratenbehandlung aktualisiert. – AXMIM

Verwandte Themen