Insert into procedure mit Bedingung

OstapBender

Benutzer
Beiträge
13
Hallo zusammen :)

Bin ganz frisch dabei MySQL zu lernen.
Habe schon Stunden damit verbracht im Internet eine Lösung zu meinem Problem zu finden. Leider ohne Erfolg. Vielleicht weiß ich auch einfach nicht, wonach ich wirklich suchen muss.

Folgendes Problem:

Ich habe mit MySQL eine Datenbank mit mehreren Tabellen entworfen.

Grundsätzlich geht es dabei um eine Vermietung.

Eine Tabelle "Vermietungen" besteht aus den Spalten "VermietungID", "vmtKundenID", "vmtGegenstandID", "vmtAbholungDatum", "vmtPlanRueckgabeDatum", "IstRueckgabeDatum"
Dabei ist VermietungID der PK, vmtKundenID ein FK, vmtGegenstandID ein FK.

Folgende Werte sollen dabei mithilfe einer gespeicherten Prozedur in die Tabelle "Vermietungen" eingetragen werden.
NameMieter, NameGegenstand, Ausleihdatum, geplanteRueckgabe

Dafür nutze ich
CREATE PROCEDURE `prcVermietung`(
MieterID int,
GegenstandID int,
Abholdatum date,
Rueckgabedatum date
)


BEGIN
insert into tblVermietungen(vmtKundenID, vmtGegengstandID, vmtAbholungDatum, vmtPlanRueckgabeDatum,)

VALUES (@KundenID, @GegenstandID, @Abholdatum, @Rueckgabedatum);
END

Soweit, so gut.

Allerdings möchte ich NUR @Gegenstände auswählen können, welche noch nicht verliehen sind. Ob ein Gegenstand verliehen ist oder nicht mach ich daran fest, ob bei der Spalte IstRueckgabeDatum kein Null Wert eingetragen ist.
Falls der Gegenstand schon verliehen ist, soll es nicht möglich sein diesen Gegenstand nochmals zu verleihen (bzw den Datensatz einzufügen).

Grundsätzlich gehts ja darum, die Auswahl der Gegenstände auf die verfügbaren Gegenstände zu reduzieren.
Falls ich also bei der Prozedur
call prcVermietungen(3,5,"2022-02-03","2022-02-28") den Gegenstand 5 auswähle (welcher bereits verliehen ist), soll kein Eintrag vorgenommen werden (optional: eine Fehlermeldung: "beispieltext" erscheinen.

Wäre super nett, wenn mir jemand bei meinem Problem helfen könnte.

Liebe Grüße
OstapBender
 
Werbung:

dabadepdu

Datenbank-Guru
Beiträge
1.123
Erstmal, gut dass Du das absichern willst.
Du kannst es mit einer Prozedur lösen und das prüfen. Du kannst bei der Auswahl der Vermietgegenstände auch nur die anbieten, die verfügbar sind.
Um zuletzt zu verhindern, dass es zu Doppelungen kommt, kannst Du einen Unique Constraint auf GegenstandID und Rückgabedatum legen. Also brauchst Du nicht unbedingt eine Prozedur.
 

akretschmer

Datenbank-Guru
Beiträge
9.848
ein unique constraint auf GegenstandID und Rückgabedatum wird IMHO nicht verhindern, daß ein und derselbe Gegenstand mehrfach da auftaucht.

Im folgenden zwei Lösungen.

a) partieller unique Index, wenn wie vom Fragesteller kein Rückgabedatum definiert ist.
Code:
postgres=# create table vermietung (werkzeug int, rueck_datum date);
CREATE TABLE
postgres=# create unique index idx1 on vermietung (werkzeug) where rueck_datum is null;
CREATE INDEX
postgres=# insert into vermietung values (1, '2022-08-02');
INSERT 0 1
postgres=# insert into vermietung values (1, null);
INSERT 0 1
postgres=# insert into vermietung values (1, null);
ERROR:  duplicate key value violates unique constraint "idx1"
DETAIL:  Key (werkzeug)=(1) already exists.
postgres=# drop table vermietung;
DROP TABLE

b) Speicherung der Datumsangaben, von-bis die Vermietung erfolgt (unter utzung von DATERANGE-Datentyp), und ein exclusion constraint, der Mehrfachvermietung verhindert:
Code:
postgres=# create table vermietung(werkzeug int, von_bis daterange, exclude using gist(werkzeug with =, von_bis with &&));
CREATE TABLE
postgres=# insert into vermietung values (1, '[2022-08-01,2022-08-10)');
INSERT 0 1
postgres=# insert into vermietung values (1, '[2022-08-010,2022-08-20)');
INSERT 0 1
postgres=# insert into vermietung values (1, '[2022-08-12,2022-08-22)');
ERROR:  conflicting key value violates exclusion constraint "vermietung_werkzeug_von_bis_excl"
DETAIL:  Key (werkzeug, von_bis)=(1, [2022-08-12,2022-08-22)) conflicts with existing key (werkzeug, von_bis)=(1, [2022-08-10,2022-08-20)).
postgres=#

Bevor Du jetzt aber anfängst: beides, also partielle Indexe und Exclusion Constraints (und auch RANGE-Typen), kann MySQL nicht. Evtl. prüfst Du noch einmal, ob Du Deine Zeit mit einer Datenbank verschwenden willst, die voller Bugs ist, dafür keinerlei coole Features bsitzt.
 

OstapBender

Benutzer
Beiträge
13
unbedingt eine Prozedur.

Hi,

erstmal danke für eure Antworten :)
@dabadepdu
Kannst du mir auch sagen wie ich das mit einer(meiner) Prozedur machen kann? Wie kann ich erst prüfen, ob zu dem zu verleihenden Gegenstand schon ein Eintrag mit NULL Wert im IstRückgabedatum vorhanden ist?

@akretmscher
In der Tabelle Vermietungen sollen ja alle Vermietungen gespeichert werden.
Ich möchte immer dann in die Tabelle einen Eintrag vornehmen, wenn ein Gegenstand ausgeliehen wird.
Wird ein Gegenstand ausgeliehen, bleibt das Feld "IstRückgabeDatum" frei bzw. Null.
Wird ein Gegenstand zurückgebracht, wird der Eintrag mit der entsprechenden VermieterID über eine Procedure geupdatet. Bei diesem Update wird dann das Rückgabedatum ausgefüllt. Ist das Rückgabedatum ausgefüllt steht der Gegenstand wieder zum Verleih bereit.
Ein doppelter Eintrag in der Tabelle Vermietung ist und soll ja also möglich sein, denn der Gegenstand kann ja durchaus öfters verliehen worden sein, darf nur nicht zur selben Zeit zweimal verliehen sein.
 

akretschmer

Datenbank-Guru
Beiträge
9.848
Kann ich das nicht auch mit MySQL lösen?
Ich nutze kein MySQL, weiß aber, daß die Features, die ich hier nutze (partielle/conditionelle Indexe, coole Daentypen, Exclusion Constraints) MySQL nicht kann. Du kannst natürlich versuchen, daß irgendwie mit einer Prozedur alles nachzubauen - es wird aber NIE so gut funktionieren wie mit diesen Features und deren native Unterstützung durch die DB. Viel Spaß!
 

akretschmer

Datenbank-Guru
Beiträge
9.848
Deine Lösung habe ich leider aufgrund mangelnder Kenntnisse nicht verstanden.
um die erste der beiden Lösungen (die einfachere und exakt auf Deine Tabelle bzw. Deine Beschreibung zugeschnittene) kurz zu erklären:
Nach Deiner Beschreibung darf es durchaus mehrere Vorgänge für einen konkreten Gegenstand geben, aber max. nur einen Vorgang mit offener Angabe des Rückgabedatums.

Daher erstelle ich einen UNIQUE INDEX auf die ID des Gegenstandes, aber mit der Einschränkung, daß das Rückgabedatum NULL, also leer ist.
Dieser UNIQUE INDEX erfaßt also nur die Gegenstände, wenn Rückgabedatum NULL ist. Da der Index als UNIQUE definiert ist, können so nur je ein solcher Eintrag im Index existieren. Das ist exakt Deine Forderung, und ich realisiere diese durch die Definition des Indexes, ohne aufwendige stored Proc oder so - ich definiere das einfach im Tabellendesign.
 

OstapBender

Benutzer
Beiträge
13
um die erste der beiden Lösungen (die einfachere und exakt auf Deine Tabelle bzw. Deine Beschreibung zugeschnittene) kurz zu erklären:
Nach Deiner Beschreibung darf es durchaus mehrere Vorgänge für einen konkreten Gegenstand geben, aber max. nur einen Vorgang mit offener Angabe des Rückgabedatums.

Daher erstelle ich einen UNIQUE INDEX auf die ID des Gegenstandes, aber mit der Einschränkung, daß das Rückgabedatum NULL, also leer ist.
Dieser UNIQUE INDEX erfaßt also nur die Gegenstände, wenn Rückgabedatum NULL ist. Da der Index als UNIQUE definiert ist, können so nur je ein solcher Eintrag im Index existieren. Das ist exakt Deine Forderung, und ich realisiere diese durch die Definition des Indexes, ohne aufwendige stored Proc oder so - ich definiere das einfach im Tabellendesign.

Danke dir für deine Erklärung. Habs dadurch besser verstanden! Eine solche Einschränkung kann ich, wie du meintest, aber nicht mit MySQL definieren, oder?
 

OstapBender

Benutzer
Beiträge
13
Da ich die Datenbank mit MySQL erstelle muss ich das wohl mit proceduren machen.

Zwar erlaubt MySQL einen UNIQUE Constraint aus der Kombination von 2 Feldern, allerdings werden NULL Werte nicht berücksichtigt. Ich könnte also einen unique constraint erstellen mit der Kombination (GegenstandID, rückgabedatum), ist das Datum allerdings null, wird dennoch eine neuer Datensatz eingefügt. Constraint gilt wohl nur, wenn GegenstandID UND Rückgabedatum identisch und NICHT NULL sind. Schade!

Hat vllt jemand eine andere Lösung? Irgendwie mit Procedure?
 

akretschmer

Datenbank-Guru
Beiträge
9.848
Hat vllt jemand eine andere Lösung? Irgendwie mit Procedure?
ein SELECT auf alle Datensätze mit GegenstandID und zählen, wie viele davon rückgabedatum NULL haben. Falls keine gefunden -> kannst Du einfügen. Falls mehrere Benutzer gleichzeitig arbeiten kann es natürlich knallen. Also Tabelle sperren. Performance dürftest Du da nicht zu viel erwarten.
 

OstapBender

Benutzer
Beiträge
13
Ich habe leider keine Ahnung wie ich das in meine Procedure einbauen kann.

CREATE PROCEDURE `prcVermietung`(
MieterID int,
GegenstandID int,
Abholdatum date,
Rueckgabedatum date
)
IF
(select Count IstRueckgabeDatum from tblVermietungen where IstRueckgabeDatum = Null) > 0
beginn
BEGIN
insert into tblVermietungen(vmtKundenID, vmtGegengstandID, vmtAbholungDatum, vmtPlanRueckgabeDatum,)

VALUES (@KundenID, @GegenstandID, @Abholdatum, @Rueckgabedatum);
END

Mein Gefühl sagt mir jetzt schon, dass das wahrscheinlich logisch und syntaxtechnisch mehr als falsch ist.

Sorry, bin echt neu in der Materie :(
 

akretschmer

Datenbank-Guru
Beiträge
9.848
Mein Gefühl sagt mir jetzt schon, dass das wahrscheinlich logisch und syntaxtechnisch mehr als falsch ist.
Dein Gefühl stimmt.

count ist eine Funktion, also count(...), ein Vergleich mit NULL via = funktioniert nicht, dafür gibt es spezielle Operatoren / Funktionen. Und ob Du in MySQL in einer procedure eine weitere Transaktion starten kannst ist mehr als fraglich...

Ich nutze kein MySQL...
 
Werbung:

OstapBender

Benutzer
Beiträge
13
Ich bin die ganze Zeit am testen und versuchen... Leider bekomme ich es nicht auf die Reihe.

Es muss doch irgendwie möglich sein nur solche Gegenstände in die Tabelle einzufügen welche ich mit einer Abfrage (verfügbare Gegenstände) auswählen kann...
 
Oben