Bulk: Einheit 1-3

This commit is contained in:
2026-03-17 20:25:47 +01:00
parent 49d6f914ff
commit e897ffe9d9
3 changed files with 388 additions and 50 deletions

View File

@@ -3,71 +3,67 @@ GO
USE "2025_5bhitn_konstantin_hintermayer_smarter_rentDB";
GO
DROP TABLE IF EXISTS Rental;
CREATE TABLE Customer
(
id BIGINT NOT NULL IDENTITY(1,1),
name VARCHAR(50) NOT NULL,
Adress VARCHAR(100) NOT NULL,
driverlicenseid VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
DROP TABLE IF EXISTS Customer;
DROP TABLE IF EXISTS [Location];
DROP TABLE IF EXISTS Vehicle;
DROP TABLE IF EXISTS VehicleCategory;
CREATE TABLE Customer (
id BIGINT NOT NULL IDENTITY (1, 1),
[name] VARCHAR(50) NOT NULL,
Adress VARCHAR(100) NOT NULL,
driverlicenseid VARCHAR(100) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Location
(
id BIGINT NOT NULL IDENTITY(1,1),
name VARCHAR NOT NULL,
address VARCHAR NOT NULL,
PRIMARY KEY (id)
CREATE TABLE Location (
id BIGINT NOT NULL IDENTITY (1, 1),
[name] VARCHAR(250) NOT NULL,
[address] VARCHAR(250) NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Rental
(
id BIGINT NOT NULL IDENTITY(1,1),
rentalStart DATETIME NOT NULL,
rentalEnd DATETIME NOT NULL,
actualEnd DATETIME NOT NULL,
customerID BIGINT NOT NULL,
vehicleID BIGINT NOT NULL,
PRIMARY KEY (id)
CREATE TABLE Rental (
id BIGINT NOT NULL IDENTITY (1, 1),
rentalStart DATETIME NOT NULL,
rentalEnd DATETIME NOT NULL,
actualEnd DATETIME NULL,
customerID BIGINT NOT NULL,
vehicleID BIGINT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE Vehicle
(
id BIGINT NOT NULL IDENTITY(1,1),
brand VARCHAR(50) NOT NULL,
model VARCHAR(50) NOT NULL,
licensePlate VARCHAR(8) NOT NULL,
buyDate DATE NOT NULL,
locationID BIGINT NOT NULL,
vehicleCategoryID BIGINT NOT NULL,
PRIMARY KEY (id)
CREATE TABLE Vehicle (
id BIGINT NOT NULL IDENTITY (1, 1),
brand VARCHAR(50) NOT NULL,
model VARCHAR(50) NOT NULL,
licensePlate VARCHAR(8) NOT NULL,
buyDate DATE NOT NULL,
locationID BIGINT NOT NULL,
vehicleCategoryID BIGINT NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE VehicleCategory
(
id BIGINT NOT NULL IDENTITY(1,1),
description Varchar NOT NULL,
pricePerDay DECIMAL NOT NULL,
PRIMARY KEY (id)
CREATE TABLE VehicleCategory (
id BIGINT NOT NULL IDENTITY (1, 1),
[description] VARCHAR(250) NOT NULL,
pricePerDay DECIMAL NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE Rental
ADD CONSTRAINT FK_Customer_TO_Rental
FOREIGN KEY (customerID)
REFERENCES Customer (id);
ADD CONSTRAINT FK_Customer_TO_Rental FOREIGN KEY (customerID) REFERENCES Customer (id);
ALTER TABLE Rental
ADD CONSTRAINT FK_Vehicle_TO_Rental
FOREIGN KEY (vehicleID)
REFERENCES Vehicle (id);
ADD CONSTRAINT FK_Vehicle_TO_Rental FOREIGN KEY (vehicleID) REFERENCES Vehicle (id);
ALTER TABLE Vehicle
ADD CONSTRAINT FK_Location_TO_Vehicle
FOREIGN KEY (locationID)
REFERENCES Location (id);
ADD CONSTRAINT FK_Location_TO_Vehicle FOREIGN KEY (locationID) REFERENCES Location (id);
ALTER TABLE Vehicle
ADD CONSTRAINT FK_VehicleCategory_TO_Vehicle
FOREIGN KEY (vehicleCategoryID)
REFERENCES VehicleCategory (id);
ADD CONSTRAINT FK_VehicleCategory_TO_Vehicle FOREIGN KEY (vehicleCategoryID) REFERENCES VehicleCategory (id);

View File

@@ -0,0 +1,137 @@
-- Insert test data into the Location table
INSERT INTO [dbo].[Location] ([name], [address])
VALUES
('Downtown Office', '123 Main St, Cityville'),
('Airport Terminal', '456 Airport Rd, Cityville'),
('City Center', '789 Central Ave, Cityville'),
('Suburban Outlet', '321 Suburb St, Cityville'),
('Train Station', '654 Rail Rd, Cityville');
-- Insert test data into the VehicleCategory table
INSERT INTO VehicleCategory ([description], [pricePerDay])
VALUES
('Compact Car', 29.99),
('SUV', 49.99),
('Luxury Sedan', 89.99),
('Minivan', 59.99),
('Pickup Truck', 69.99);
-- Insert test data into the Vehicle table
INSERT INTO Vehicle (brand, model, licensePlate, buyDate, locationID, vehicleCategoryID)
VALUES
('Toyota', 'Corolla', 'ABC1234', '2020-06-15', 1, 1),
('Honda', 'CR-V', 'XYZ5678', '2019-03-22', 2, 2),
('BMW', '5 Series', 'LMN9012', '2021-01-10', 3, 3),
('Ford', 'Transit', 'GHI3456', '2020-11-05', 4, 4),
('Chevrolet', 'Silverado', 'JKL7890', '2018-07-19', 5, 5);
-- Insert test data into the Customer table
INSERT INTO Customer (name, Adress, driverlicenseid)
VALUES
('John Doe', '1 Elm St, Cityville', 'D123456789'),
('Jane Smith', '2 Oak St, Cityville', 'D987654321'),
('Bob Johnson', '3 Pine St, Cityville', 'D456123789'),
('Alice Williams', '4 Maple St, Cityville', 'D654789123'),
('Charlie Brown', '5 Cedar St, Cityville', 'D321654987');
GO
-- ########################################################
-- # Views #
-- ########################################################
-- View: v_VerfuegbareFahrzeuge
-- Zeigt Fahrzeuge an, die nicht vermietet sind oder deren Rückgabedatum in der Vergangenheit liegt
CREATE OR ALTER VIEW v_VerfuegbareFahrzeuge AS
SELECT
v.id,
v.brand,
v.model,
v.licensePlate,
vc.description AS category,
vc.pricePerDay,
l.name AS location,
l.address AS locationAddress,
CASE
WHEN r.id IS NULL THEN 'Available'
WHEN r.rentalEnd < CAST(GETDATE() AS DATE) THEN 'Available (Overdue Return)'
ELSE 'Not Available'
END AS status
FROM Vehicle v
JOIN VehicleCategory vc ON v.vehicleCategoryID = vc.id
JOIN Location l ON v.locationID = l.id
LEFT JOIN Rental r ON v.id = r.vehicleID AND r.actualEnd IS NULL
WHERE r.id IS NULL OR r.actualEnd < CAST(GETDATE() AS DATE);
GO
-- View: v_UmsatzProKategorie
-- Zeigt den kumulierten Umsatz pro Fahrzeugkategorie an
CREATE OR ALTER VIEW v_UmsatzProKategorie AS
SELECT
vc.id,
vc.description AS category,
vc.pricePerDay,
COUNT(r.id) AS totalRentals,
SUM(
DATEDIFF(DAY, r.rentalStart, COALESCE(r.rentalEnd, CAST(GETDATE() AS DATE)))
* vc.pricePerDay
) AS totalRevenue
FROM VehicleCategory vc
LEFT JOIN Vehicle v ON vc.id = v.vehicleCategoryID
LEFT JOIN Rental r ON v.id = r.vehicleID
GROUP BY
vc.id,
vc.description,
vc.pricePerDay;
GO
-- ########################################################
-- # User Defined Functions #
-- ########################################################
-- Scalar Function: fn_BerechneMietkosten
CREATE OR ALTER FUNCTION fn_BerechneMietkosten (
@StartDatum DATE,
@EndDatum DATE,
@Tagespreis DECIMAL(10, 2)
)
RETURNS DECIMAL(10, 2)
AS
BEGIN
DECLARE @AnzahlTage INT;
DECLARE @Mietkosten DECIMAL(10, 2);
-- Berechne die Anzahl der Tage (mindestens 1 Tag)
SET @AnzahlTage = DATEDIFF(DAY, @StartDatum, @EndDatum);
-- Falls das Enddatum vor oder gleich dem Startdatum ist, sind es mindestens 1 Tag
IF @AnzahlTage < 1
SET @AnzahlTage = 1;
-- Berechne die Gesamtkosten
SET @Mietkosten = @AnzahlTage * @Tagespreis;
RETURN @Mietkosten;
END;
GO
-- Table-Valued Function: fn_FahrzeugeAnStandort
CREATE OR ALTER FUNCTION fn_FahrzeugeAnStandort (
@StandortID INT
)
RETURNS TABLE
AS
RETURN (
SELECT
v.id,
v.brand,
v.model,
v.licensePlate,
v.buyDate,
vc.description AS category,
vc.pricePerDay,
l.name AS locationName,
l.address AS locationAddress
FROM Vehicle v
JOIN VehicleCategory vc ON v.vehicleCategoryID = vc.id
JOIN Location l ON v.locationID = l.id
WHERE v.locationID = @StandortID
);

View File

@@ -0,0 +1,205 @@
-- ####################################################
-- # STORED PROCEDURES #
-- ####################################################
-- Stored Procedure: sp_MieteFahrzeug
CREATE OR ALTER PROCEDURE sp_MieteFahrzeug
@KundeID BIGINT,
@FahrzeugID BIGINT,
@Start DATE,
@Ende DATE
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @VerfuegbareFahrzeuge INT;
BEGIN TRY
BEGIN TRANSACTION;
-- Prüfe, ob Kunde existiert
IF NOT EXISTS (SELECT 1 FROM Customer WHERE id = @KundeID)
BEGIN
RAISERROR('Kunde mit der angegebenen ID existiert nicht.', 16, 1);
END;
-- Prüfe, ob Fahrzeug existiert
IF NOT EXISTS (SELECT 1 FROM Vehicle WHERE id = @FahrzeugID)
BEGIN
RAISERROR('Fahrzeug mit der angegebenen ID existiert nicht.', 16, 1);
END;
-- Prüfe, ob Enddatum nach Startdatum liegt
IF @Ende <= @Start
BEGIN
RAISERROR('Das Enddatum muss nach dem Startdatum liegen.', 16, 1);
END;
-- Prüfe Verfügbarkeit des Fahrzeugs
SELECT @VerfuegbareFahrzeuge = COUNT(*)
FROM Rental
WHERE vehicleID = @FahrzeugID
-- Ein Fahrzeug ist besetzt, wenn der neue Zeitraum sich mit einem bestehenden überschneidet
-- und noch nicht zurückgegeben wurde (actualEnd IS NULL)
AND actualEnd IS NULL
AND (
(@Start < rentalEnd)
AND (@Ende > rentalStart)
);
IF @VerfuegbareFahrzeuge > 0
BEGIN
RAISERROR('Das Fahrzeug ist im angegebenen Zeitraum nicht verfügbar.', 16, 1);
END;
-- Erstelle den Mietdatensatz
-- Hinweis: actualEnd ist initial NULL
INSERT INTO Rental (customerID, vehicleID, rentalStart, rentalEnd, actualEnd)
VALUES (@KundeID, @FahrzeugID, @Start, @Ende, NULL);
DECLARE @MietID BIGINT = SCOPE_IDENTITY();
COMMIT TRANSACTION;
-- Rückgabewert
SELECT
@MietID AS id,
'Mietvertrag erfolgreich erstellt.' AS message,
@Start AS rentalStart,
@Ende AS rentalEnd;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE @ErrMssp_MieteFahrzeug NVARCHAR(4000) = ERROR_MESSAGE();
RAISERROR(@ErrMssp_MieteFahrzeug, 16, 1);
END CATCH;
END;
GO
-- Stored Procedure: sp_RueckgabeFahrzeug
-- Aktualisiert actualEnd und berechnet Endpreis via UDF
-- Stored Procedure: sp_RueckgabeFahrzeug
-- Aktualisiert actualEnd und berechnet Endpreis via UDF
CREATE OR ALTER PROCEDURE sp_RueckgabeFahrzeug
@MietID BIGINT,
@RueckgabeDatum DATETIME
AS
BEGIN
SET NOCOUNT ON;
SET XACT_ABORT ON;
DECLARE @Tagespreis DECIMAL(10, 2);
DECLARE @StartDatum DATE;
DECLARE @Endpreis DECIMAL(10, 2);
BEGIN TRY
BEGIN TRANSACTION;
-- Prüfe, ob Miet-ID existiert
IF NOT EXISTS (SELECT 1 FROM Rental WHERE id = @MietID)
BEGIN
RAISERROR('Mietvertrag mit der angegebenen ID existiert nicht.', 16, 1);
END;
-- Hole Start-Datum und Tagespreis (aus VehicleCategory via Vehicle)
SELECT
@StartDatum = r.rentalStart,
@Tagespreis = vc.pricePerDay
FROM Rental r
JOIN Vehicle v ON r.vehicleID = v.id
JOIN VehicleCategory vc ON v.vehicleCategoryID = vc.id
WHERE r.id = @MietID;
-- Berechne den Endpreis mit Hilfe der UDF aus Einheit 2
SET @Endpreis = dbo.fn_BerechneMietkosten(@StartDatum, @RueckgabeDatum, @Tagespreis);
-- Prüfe, ob Rückgabedatum nach Startdatum liegt
IF @RueckgabeDatum < @StartDatum
BEGIN
RAISERROR('Das Rückgabedatum kann nicht vor dem Mietstart liegen.', 16, 1);
END;
-- Aktualisiere den Rental-Datensatz (actualEnd)
UPDATE Rental
SET
actualEnd = @RueckgabeDatum
WHERE id = @MietID;
COMMIT TRANSACTION;
-- Rückgabewert
SELECT
@MietID AS id,
'Fahrzeug erfolgreich zurückgegeben.' AS message,
@RueckgabeDatum AS actualEnd,
@Endpreis AS calculatedTotalPrice;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE @ErrMssp_RueckgabeFahrzeug NVARCHAR(4000) = ERROR_MESSAGE();
RAISERROR(@ErrMssp_RueckgabeFahrzeug, 16, 1);
END CATCH;
END;
GO
-- =====================================================
-- TRIGGER
-- =====================================================
-- Hinweis: Die Status-Update Trigger wurden entfernt, da die Tabelle 'Vehicle'
-- laut Schema keine 'status' Spalte besitzt. Die Verfügbarkeit wird
-- dynamisch über Views (v_VerfuegbareFahrzeuge) ermittelt.
-- Archive table for Customer (if not exists)
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='CustomerArchiv' AND xtype='U')
BEGIN
CREATE TABLE CustomerArchiv (
id BIGINT NOT NULL,
name VARCHAR(50) NOT NULL,
Adress VARCHAR(100) NOT NULL,
driverlicenseid VARCHAR(100) NOT NULL,
deletedDate DATETIME NOT NULL,
PRIMARY KEY (id, deletedDate)
);
END;
GO
-- Trigger: trg_Archivierung
-- Kopiert gelöschte Kunden in KundenArchiv-Tabelle statt physisch zu löschen
CREATE OR ALTER TRIGGER trg_Archivierung
ON Customer
INSTEAD OF DELETE
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
BEGIN TRANSACTION;
-- Kopiere gelöschte Kunden in die Archiv-Tabelle
INSERT INTO CustomerArchiv (id, name, Adress, driverlicenseid, deletedDate)
SELECT
id,
name,
Adress,
driverlicenseid,
GETDATE()
FROM deleted;
-- Lösche den Datensatz nur, wenn die Archivierung erfolgreich war
DELETE FROM Customer
WHERE id IN (SELECT id FROM deleted);
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
DECLARE @ErrMsstrg_Archivierung NVARCHAR(4000) = ERROR_MESSAGE();
RAISERROR(@ErrMsstrg_Archivierung, 16, 1);
END CATCH;
END;
GO