From e897ffe9d938f5028bc9fb879a6280e09d8c5189 Mon Sep 17 00:00:00 2001 From: KoCoder Date: Tue, 17 Mar 2026 20:25:47 +0100 Subject: [PATCH] Bulk: Einheit 1-3 --- ...N_Konstantin_Hintermayer_create_schema.sql | 96 ++++---- ...N_Konstantin_Hintermayer_seed_database.sql | 137 ++++++++++++ ...in_Hintermayer_procedures_and_triggers.sql | 205 ++++++++++++++++++ 3 files changed, 388 insertions(+), 50 deletions(-) create mode 100644 Einheit_2/2025_5BHITN_Konstantin_Hintermayer_seed_database.sql create mode 100644 Einheit_3/2025_5BHITN_Konstantin_Hintermayer_procedures_and_triggers.sql diff --git a/Einheit_1/2025_5BHITN_Konstantin_Hintermayer_create_schema.sql b/Einheit_1/2025_5BHITN_Konstantin_Hintermayer_create_schema.sql index 83f549f..75b0084 100644 --- a/Einheit_1/2025_5BHITN_Konstantin_Hintermayer_create_schema.sql +++ b/Einheit_1/2025_5BHITN_Konstantin_Hintermayer_create_schema.sql @@ -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); \ No newline at end of file +ADD CONSTRAINT FK_VehicleCategory_TO_Vehicle FOREIGN KEY (vehicleCategoryID) REFERENCES VehicleCategory (id); \ No newline at end of file diff --git a/Einheit_2/2025_5BHITN_Konstantin_Hintermayer_seed_database.sql b/Einheit_2/2025_5BHITN_Konstantin_Hintermayer_seed_database.sql new file mode 100644 index 0000000..1aebedc --- /dev/null +++ b/Einheit_2/2025_5BHITN_Konstantin_Hintermayer_seed_database.sql @@ -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 +); \ No newline at end of file diff --git a/Einheit_3/2025_5BHITN_Konstantin_Hintermayer_procedures_and_triggers.sql b/Einheit_3/2025_5BHITN_Konstantin_Hintermayer_procedures_and_triggers.sql new file mode 100644 index 0000000..81683ef --- /dev/null +++ b/Einheit_3/2025_5BHITN_Konstantin_Hintermayer_procedures_and_triggers.sql @@ -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 \ No newline at end of file