Montag, 17. Juli 2006
Primärschlüssel Korrektur
Es ist lästig.

Man hat eine schöne Firebird Datenbank mit Generatoren (Oder Sequences) um Primärschlüssel zu füllen und dann leert man die DB um vor der scharfen Verwendung noch einmal sauber Daten zu importieren.

Dann passen die Generatoren aber nicht mehr und werden unnötig gross.

Ja, ich weis, es ist nur Kosmetik, aber warum nicht.

Hier eine Prozedur, die - wenn die Namenskonvention GEN__<field> eingehalten ist (wobei <field> auch weggelassen sein kann), Generatoren zu Tabellen findet, ein SELECT MAX(*) .. macht und den Generator entsprechend korrigiert.

SET TERM ^ ;

CREATE PROCEDURE "PROCSYS_DBCheckPKValues" (
"ShowOnly" SMALLINT,
"HideNothingToDo" SMALLINT)
RETURNS (
"Name" VARCHAR(32),
"MaxId" BIGINT,
"MaxGen" BIGINT,
"Message" VARCHAR(80),
"GenName" VARCHAR(32))
AS
DECLARE VARIABLE Q VARCHAR(1000);
DECLARE VARIABLE "Gen" VARCHAR(32);
DECLARE VARIABLE "Count" BIGINT;
begin
if ("ShowOnly" IS NULL) then
"ShowOnly" = 1;

if ("HideNothingToDo" IS NULL) then
"HideNothingToDo" = 1;

FOR SELECT RDB$RELATION_NAME --, RDB$DESCRIPTION
FROM RDB$RELATIONS R
WHERE RDB$VIEW_BLR IS NULL AND RDB$SYSTEM_FLAG = 0
-- AND (((RDB$RELATION_NAME starting with 'FAU') AND (RDB$RELATION_NAME containing '_')) OR (RDB$RELATION_NAME = 'DBINFO'))
ORDER BY 1
INTO :"Name" --, :"Description"
DO BEGIN

"Name" = RTrim("Name");

"Message" = '';
BEGIN
"MaxId" = NULL;
Q = 'SELECT CAST(Max("Id") AS BIGINT), CAST(Count("Id") AS BIGINT) FROM "'|| "Name"||'";';
EXECUTE STATEMENT Q INTO :"MaxId", :"Count";
WHEN ANY DO
"MaxId" = NULL;
END

if ("MaxId" IS NULL) then begin
"MaxId" = NULL;
Q = 'SELECT CAST(Max("ID") AS BIGINT), CAST(Count("ID") AS BIGINT) FROM "'|| "Name"||'";';
EXECUTE STATEMENT Q INTO :"MaxId", :"Count";
WHEN ANY DO
"MaxId" = NULL;
end

BEGIN
"Gen" = 'GEN_'||"Name"||'_ID'; -- Gesuchert Name

"GenName" = NULL; -- Echter Name
SELECT RDB$GENERATOR_NAME
FROM RDB$GENERATORS
WHERE ((RDB$SYSTEM_FLAG IS NULL) or (RDB$SYSTEM_FLAG = 0)) AND UPPER(RDB$GENERATOR_NAME) = UPPER(:"Gen")
INTO :"GenName";

if ("GenName" IS NULL) then begin
"Gen" = 'GEN_'||"Name";
--"GenName" = NULL;
SELECT RDB$GENERATOR_NAME
FROM RDB$GENERATORS
WHERE ((RDB$SYSTEM_FLAG IS NULL) or (RDB$SYSTEM_FLAG = 0)) AND UPPER(RDB$GENERATOR_NAME) = UPPER(:"Gen")
INTO :"GenName";
end

if ("GenName" IS NOT NULL) then begin
"GenName" = RTrim("GenName");
"MaxGen" = NULL;
Q = 'SELECT GEN_ID("'||:"GenName"||'",0) FROM RDB$DATABASE;';
EXECUTE STATEMENT Q INTO :"MaxGen";
end else
"MaxGen" = NULL;
WHEN ANY DO
"MaxGen" = NULL;
END

if ("MaxId" IS NULL) then begin
if ("Count" = 0) then begin
-- "Message" = 'Tabelle ist leer!';
"MaxId" = 0; -- Bei leerer Tabelle Wert auf 0 setzen
end else
"Message" = 'Tabelle hat kein Standardformat oder Sie keine Rechte!';
end else if ("MaxGen" IS NULL) then
"Message" = 'Generator '|| COALESCE("GenName","Gen",'ohne Namen') || ' nicht gefunden oder keine Rechte!';


if ("Message" = '') then begin
if ("MaxGen" <> "MaxId") then begin -- Korrektur notwendig --
if ("ShowOnly" = 0) then begin
"Message" = 'Generator korrigiert um '|| (:"MaxId"-:"MaxGen");
Q = 'SET GENERATOR "'||:"GenName"|| '" to '|| "MaxId"||';';
EXECUTE STATEMENT Q;
WHEN ANY DO
"Message" = 'Fehler bei Korrektur des Generators '||"GenName";
end else begin
-- ShowOnly = 1
"Message" = 'Generator sollte korrigiert werden um '|| (:"MaxId"-:"MaxGen");
end

if ("HideNothingToDo" = 1) then
suspend;

end else begin
"Message" = 'Generator und Tabelle passen zusammen';
end
end -- If

if ("HideNothingToDo" <> 1) then
suspend;
end -- FOR SELECT
end^

SET TERM ; ^

DESCRIBE PROCEDURE "PROCSYS_DBCheckPKValues"
'Überprüft alle Primärschlüssel-Werte und passt ggf. Generatoren AND, die in der Form GEN_<TABLENAME>_ID sind';

DESCRIBE PARAMETER "ShowOnly" PROCEDURE "PROCSYS_DBCheckPKValues"
'1= Nur Anzeige, sonst auch korrigieren';

DESCRIBE PARAMETER "HideNothingToDo" PROCEDURE "PROCSYS_DBCheckPKValues"
'1 = Verstecke alle, bei denen nichts zu tun ist';

... comment