AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Datenbanken Delphi Records mit einem Unique Key in Lücke aufrücken lassen
Thema durchsuchen
Ansicht
Themen-Optionen

Records mit einem Unique Key in Lücke aufrücken lassen

Ein Thema von QuickAndDirty · begonnen am 30. Dez 2022 · letzter Beitrag vom 17. Apr 2023
Antwort Antwort
Seite 1 von 2  1 2      
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.926 Beiträge
 
Delphi 12 Athens
 
#1

Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 30. Dez 2022, 12:49
Datenbank: FB und MSSQL • Version: 2.5 und ? • Zugriff über: Firedac
Hallo wie kann ich Records in einem Feld mit Unique Key am Besten aufrücken lassen?
Wichtig dafür ist, dass keine SQL dialekt spezifischen fuktionen benutzt werden dürfen.
Z.b. Firebird hat "order by" in Updates aber leider hat MSSQL das nicht und irgendwie hat das keiner.

Angebnommen ich habe eine Tabelle
Code:
Gruppen
mit Feldern wie
Code:
ID INT, GruppenID INT, Position INT
und ein Unique Key für
Code:
GruppenID, Position
Wenn ich jetzt einen Record lösche möchte ich das die Records mit einer höheren Position in der Gruppe in die Lücke aufrücken.

Code:
UPDATE GRUPPEN
SET POSITION = POSITION-1 
WHERE GRUPPENID = :GRUPPENID
  AND POSITION > :POSITION
Ohne Unique Key geht das, aber mit Unique Key kann es zu Key Violations kommen je nach dem in welcher Reihenfolge die Updates durchgeführt werden.

Ich mache es jetzt quasi "von hand" in der richtigen reihen folge und es sieht aus wie viel zu viel Aufwand für ein einfaches löschen eines Datensatzes...

Gibt es einen besseren weg??????

Ich hab schon überlegt es wie folgt zu machen
Code:
UPDATE GRUPPEN
SET POSITION = POSITION * (-1)
WHERE GRUPPENID = :GRUPPENID
  AND POSITION > :POSITION;

UPDATE GRUPPEN
SET POSITION = ( POSITION * (-1) ) -1 
WHERE GRUPPENID = :GRUPPENID
  AND POSITION < 0;
also erstmal die werte auf negative werte setzen und sie dann auf den gewollten wert setzen um Duplikate zu vermeiden.

Vieleicht macht es auch sinn für den zweck die Tabelle und den Unique Key zu erweitern um ein feld
Code:
OLDPOSITION INT
Dann könnte man es so machen.
Code:
UPDATE GRUPPEN
SET OLDPOSITION = POSITION
WHERE GRUPPENID = :GRUPPENID
  AND POSITION > :POSITION;

UPDATE GRUPPEN
SET POSITION = OLDPOSITION-1
WHERE GRUPPENID = :GRUPPENID
  AND OLDPOSITION> :POSITION;

UPDATE GRUPPEN
SET OLDPOSITION = NULL
WHERE GRUPPENID = :GRUPPENID;
Durch OLDPOSITION im Unique Key hätte man für das aufrücken etwas spielraum und mit dem NULL setzen von OLD position würde man die UNIQUE KEY Constraint auf Position wieder aktivieren...

Gibt's ein verfahren das quasi der Industrie-standard ist?
Andreas
Monads? Wtf are Monads?

Geändert von QuickAndDirty (30. Dez 2022 um 12:55 Uhr)
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.275 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 30. Dez 2022, 14:15
Hallo,
der "Industriestandard" ist, gar nichts zu tun.

Unique Keys sind künstliche Schlüssel.
Warum sollte man da nach dem Anlegen noch irgendwas ändern?
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.442 Beiträge
 
Delphi 12 Athens
 
#3

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 30. Dez 2022, 15:04
Das funktioniert sowieso nur halbwegs konsistent, wenn es zusätzlich zu dem Unique-Key-Feld noch ein ID-Feld pro Datensatz gibt, welches sich niemals ändert. Wenn der Unique Key nicht nur zur Sortierung, sondern auch zur Identifikation verwendet wird, sollte er sich nie ändern.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Delphi.Narium

Registriert seit: 27. Nov 2017
2.490 Beiträge
 
Delphi 7 Professional
 
#4

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 30. Dez 2022, 15:42
1. Eindeutige Schlüssel ändert man nicht.

2. In Firebird könnte es so aussehen:
SQL-Code:
select 'update gruppen set position = '||row_number() over ()||' where gruppenid = '||gruppenid||' and id = '||id as sql
from gruppen where gruppenid = :GruppenID order by id
3. In MSSQL könnte es so aussehen:
SQL-Code:
select concat('update gruppen set position = ',row_number() over (),' where gruppenid = ',id,' and id = ',g.id,';') as sql
from gruppen where gruppenid = :Gruppenid order by id
Firebird baut Strings halt mit || zusammen, MSSQL mit Concat.

Damit FireBird auch mit Concat arbeiten kann, muss man sich eine passende Funktion bauen, die dann in die Scripte zum Datenbankaufbau mit rein muss:
SQL-Code:
SET TERM !!;
CREATE or alter function concat (
v1 varchar(2000),
v2 varchar(2000) default '',
v3 varchar(2000) default '',
v4 varchar(2000) default '',
v5 varchar(2000) default '',
v6 varchar(2000) default '',
v7 varchar(2000) default '',
v8 varchar(2000) default '',
v9 varchar(2000) default ''
)
returns varchar(2000)
AS
BEGIN
  return v1||v2||v3||v4||v5||v6||v7||v8||v9;
END!!
SET TERM ;!!
Nachteil: Concat von MSSQL kann bis zu 254 Parameter annehmen, die aber nicht angegeben werden müssen.
Ob diese "Wahlfreiheit" bei FireBird möglich ist, hab' ich nicht herausbekommen. Bei obiger Lösung müssen sie alle angegeben werden (deshalb hab' ich mal bei neun Parametern aufgehört).

Als Ergebnis käme ein SQL heraus, das dann unter MSSQL und FireBird funktionieren sollte:
SQL-Code:
select concat('update gruppen set position = ',row_number() over (),' where gruppenid = ',id,' and id = ',id,';','','') as sql
from gruppen where gruppenid = :Gruppenid order by id
Die als Ergebnis erstellten Updatestatements müssten nun noch in 'ner Schleife, einem Executeblockkonstrukt, das für beide Datenbanken praktikabel ist, o. ä. ausgeführt werden.

Und nein, es ist keine gute Idee, einen eindeutigen Schlüssel zu ändern.

Wird hier der "Unique Key" nur als "datenbankseitige Hilfe" genutzt, um auf Fehler beim Setzen der Position hinzuweisen, mag es angehen. Es muss aber sichergestellte sein, dass niemand, wirklich niemand, die Kombination von GruppenID und Position in irgendeiner Form (ggfls., unter Umständen eventuell, vielleicht, auch nur ansatzweise) als Schlüssel verwendet. Flapsig formuliert: Der "Unique Key" darf alles sein, nur kein "Unique Key", sondern nur ein Konstrukt, das "irgendwie (datenbankseitig) geeignet ist", Positionsdubletten innerhalb einer GruppenID zu verhindern.

Funktioniert die Lösung?

Vielleicht.

Ist sie Industriestandard oder etwas, das diesem (wenn auch nur ansatzweise) ähnlich sein könnte?

Nein, sicherlich nicht.

Hilft sie bei der Behebung eines Problemes, das bisher unter "Missbrauch" eines "Unique Keys" gelöst werden konnte?

Eventuell.

PS: Funktion und SQL funktionieren unter FireBird. MSSQL hab' ich nicht, daher kann ich hier nur darauf hoffen, dass es funktionieren könnte. Als Idee sollte es aber ausreichen.

Geändert von Delphi.Narium (31. Dez 2022 um 13:01 Uhr) Grund: Schreibfehler
  Mit Zitat antworten Zitat
jobo

Registriert seit: 29. Nov 2010
3.072 Beiträge
 
Delphi 2010 Enterprise
 
#5

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 30. Dez 2022, 17:48
Es wurde ja schon sehr deutlich geschrieben, dass man das nicht macht. Und es gibt viele gute Gründe dafür.
Vielleicht noch zur Anti- Motivation:
Wenn der Grund, es dennoch zu tun, darin liegt, dass sonst irgendetwas in der Anwendung nicht funktioniert, dann sollte diese Stelle repariert werden, statt PK ID Lücken zu füllen.
Ein PK (und entsprechend FK) hat keine andere Funktion als die Schlüsselfunktion, also Eindeutigkeit. Er ist kein fachlicher Nachschlagewert, dient nicht zur Sortierung, ist nicht gleichschrittig aufgebaut, nicht aufsteigend und bildet keine Zusatz- / Geheim- Informationen über das Produkt ab.
Gruß, Jo
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.926 Beiträge
 
Delphi 12 Athens
 
#6

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 10. Mär 2023, 15:08
Es wird benutzt um Positions-Dubletten innehalb einer Gruppe zu verhindern. Jeder Datensatz hat eine eindeutige ID.....der Primärschlüssel halt .
Ich wusste nicht das diese Funktionalität von Schlüsseln ein Missbrauch ist. Dachte an sich immer, dass es weitverbreitete Praxis ist.
Andreas
Monads? Wtf are Monads?
  Mit Zitat antworten Zitat
Redeemer

Registriert seit: 19. Jan 2009
Ort: Kirchlinteln (LK Verden)
1.049 Beiträge
 
Delphi 2009 Professional
 
#7

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 11. Mär 2023, 07:31
Wie können beim Löschen Dubletten auftreten?
Janni
2005 PE, 2009 PA, XE2 PA
  Mit Zitat antworten Zitat
Benutzerbild von Jasocul
Jasocul

Registriert seit: 22. Sep 2004
Ort: Delmenhorst
1.354 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 13. Mär 2023, 10:19
Ich glaube fast, dass es hier ein generelles Missverständnis gibt.
Der PK ist das Feld "ID".
Dann gibt es zusätzlich eine GruppenID und eine Position, die in Kombination ein UK sind.
Wenn ich dabei an eine WaWi denke, könnte GruppenID eine Auftragsnummer sein und Position die laufende Positionsnummer.
Löscht man eine der Position (z.B. Nr 3 von 500), möchte man die Positionsnummern neu vergeben, damit keine Lücken entstehen.
Die Aussage, dass das eine Prüfung der Dubletten sein soll, ist vermutlich unglücklich formuliert. Ich gehe davon aus, dass durch den kombinierten UK doppelte Positionsnummern in einem "Auftrag" bei der Erfassung verhindert werden sollen. Es stellt sich dabei natürlichdie Frage, wie das passieren sollte, da man üblicherweise Positionsnummern nicht manuell vergibt, aber das ist ein anderes Thema.

Firebird kennt "with" und das gilt inzwischen eigentlich für alle aktuellen Datenbanken.
Nimmt man in das With eine sortierte SQL-Abfrage und joined das im Update-Statement, kann man vermutlich die Positionen neu durchnummerieren.
Bitte selbst testen, da es nicht schwierig ist und ich auch kein Firebird zur Verfügung habe, um das zu prüfen.
Peter
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.926 Beiträge
 
Delphi 12 Athens
 
#9

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 17. Mär 2023, 12:07
Ich glaube fast, dass es hier ein generelles Missverständnis gibt.
Der PK ist das Feld "ID".
Dann gibt es zusätzlich eine GruppenID und eine Position, die in Kombination ein UK sind.
Wenn ich dabei an eine WaWi denke, könnte GruppenID eine Auftragsnummer sein und Position die laufende Positionsnummer.
Löscht man eine der Position (z.B. Nr 3 von 500), möchte man die Positionsnummern neu vergeben, damit keine Lücken entstehen.
Die Aussage, dass das eine Prüfung der Dubletten sein soll, ist vermutlich unglücklich formuliert. Ich gehe davon aus, dass durch den kombinierten UK doppelte Positionsnummern in einem "Auftrag" bei der Erfassung verhindert werden sollen. Es stellt sich dabei natürlichdie Frage, wie das passieren sollte, da man üblicherweise Positionsnummern nicht manuell vergibt, aber das ist ein anderes Thema.

Firebird kennt "with" und das gilt inzwischen eigentlich für alle aktuellen Datenbanken.
Nimmt man in das With eine sortierte SQL-Abfrage und joined das im Update-Statement, kann man vermutlich die Positionen neu durchnummerieren.
Bitte selbst testen, da es nicht schwierig ist und ich auch kein Firebird zur Verfügung habe, um das zu prüfen.
Ich lese mir mal "With" durch!
Andreas
Monads? Wtf are Monads?
  Mit Zitat antworten Zitat
QuickAndDirty

Registriert seit: 13. Jan 2004
Ort: Hamm(Westf)
1.926 Beiträge
 
Delphi 12 Athens
 
#10

AW: Records mit einem Unique Key in Lücke aufrücken lassen

  Alt 17. Mär 2023, 12:16
Wie können beim Löschen Dubletten auftreten?
Beim Löschen keine!
Beim Aufrücken in die freie Position kann das passieren je nach dem in welcher reihenfolge der SQLServer die Datensätze bearbeitet.
Code:
UPDATE "TABELLE" SET "ZEILENPOSITION" = "ZEILENPOSITION" -1
Wenn UPDATE zuerst Datensätze mit der kleinsten "ZEILENPOSITION" bearbeitet dann haben wir keine Doubletten
Wenn UPDATE aber mit einer Anderen "ZEILENPOSITION" beginnt als mit der Kleinsten, dann havben wir temporär Doubletten und die UNIQUE KEY CONSTRAINT schlägt zu.
Andreas
Monads? Wtf are Monads?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 18:11 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz