Autor Beitrag
CBRABO
Hält's aus hier
Beiträge: 10

WinXP
Delphi 2007 pro
BeitragVerfasst: So 23.09.07 13:04 
Hallo Zusammen!

Nachdem ich ohne Ende Ärger mit der BDE hatte, habe ich mich nun durchgerungen, mein aktuelles Projekt vollständig auf den Firebase embedded umzustellen. Das Anlegen mit der IBOConsole hat auch alles super geklappt und ich muss gestehen, ich bin auch sehr begeistert davon.

Zunächst hatte ich überlegt, sämtliche TTable-Komponenten einfach gegen TIBTable zu tauschen. Da aber ohnehin noch einiges an Umstellungsaufwand notwendig ist und ich nun ohnehin die ganze Anwendung nochmal auseinandernehmen muss, wollte es dann auch ordentlich machen und gleich mit TIBDataSet arbeiten.

Leider gelingt mir jedoch die Master-Detail-Verknüpfung noch nicht richtig. Auch die Recherche in verschiedenen Foren und auch Google hat mich nicht wirklich zum Ziel führen können.

Ich habe zunächst nur mal mit zwei Tabellen begonnen. In der Tabelle T_Objekt gibt es die Felder ID_OBJEKT, STRASSE, PLZ, ORT, INDABRTEXT und in der Tabelle T_Jahr gibt es die Felder ID_JAHR, ID_OBJEKT, JAHR. Ziel ist es, zu jedem Objekt eine beliebige Zahl von Jahren anzulegen.

Die META-Daten:

ausblenden volle Höhe SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
SET SQL DIALECT 3;

/* CREATE DATABASE 'NK2007.fdb' PAGE_SIZE 4096

DEFAULT CHARACTER SET NONE */

/* Domain definitions */
CREATE DOMAIN "BOOL" AS SMALLINT
CHECK ((VALUE = 0) OR (VALUE = 1));
CREATE DOMAIN "DECIMALANTEILE" AS DECIMAL(9, 4);
CREATE DOMAIN "EURO" AS DECIMAL(9, 2);
CREATE DOMAIN "FLOATQM" AS FLOAT
CHECK (VALUE >= 0);
CREATE DOMAIN "INTID" AS INTEGER;
CREATE DOMAIN "INTJAHR" AS INTEGER
CHECK ((VALUE >= 1900) AND (VALUE <= 2099));
CREATE DOMAIN "INTSORT" AS INTEGER;
CREATE DOMAIN "SMALLINT" AS SMALLINT;
CREATE DOMAIN "STR10" AS VARCHAR(10);
CREATE DOMAIN "STR100" AS VARCHAR(100);
CREATE DOMAIN "STR20" AS VARCHAR(20);
CREATE DOMAIN "STR250" AS VARCHAR(250);
CREATE DOMAIN "STR30" AS VARCHAR(30);
CREATE DOMAIN "STR50" AS VARCHAR(50);

/* Table: T_JAHR, Owner: SYSDBA */

CREATE TABLE "T_JAHR" 
(
"ID_JAHR" INTID NOT NULL,
"ID_OBJEKT" INTID NOT NULL,
"JAHR" INTJAHR ,
CONSTRAINT "PK_T_JAHRE" PRIMARY KEY ("ID_JAHR")
);

/* Table: T_OBJEKT, Owner: SYSDBA */

CREATE TABLE "T_OBJEKT" 
(
"ID_OBJEKT" INTID NOT NULL,
"STRASSE" STR50 ,
"PLZ" STR10 ,
"ORT" STR50 ,
"INDABRTEXT" STR250 ,
"BEMERKUNG" STR250 ,
CONSTRAINT "PK_T_OBJEKT" PRIMARY KEY ("ID_OBJEKT")
);

/* Index definitions for all user tables */

CREATE INDEX "IDX_T_OBJEKT_STRASSE" ON "T_OBJEKT"("STRASSE");
ALTER TABLE "T_JAHR" ADD CONSTRAINT "FK_T_JAHR_OBJEKT" FOREIGN KEY ("ID_OBJEKT") REFERENCES "T_OBJEKT" ("ID_OBJEKT") ON UPDATE CASCADE ON DELETE CASCADE;

CREATE GENERATOR "GEN_JAHR_ID";
CREATE GENERATOR "GEN_OBJEKT_ID";
SET TERM ^ ;


/* Triggers only will work for SQL triggers */

CREATE TRIGGER "TRIG_JAHR_ID" FOR "T_JAHR" 
ACTIVE BEFORE INSERT POSITION 0
as
BEGIN
NEW.ID_JAHR = GEN_ID (GEN_JAHR_ID, 1);
END
^

CREATE TRIGGER "TRIG_OBJEKT_ID" FOR "T_OBJEKT" 
ACTIVE BEFORE INSERT POSITION 0
as
BEGIN
NEW.ID_OBJEKT = GEN_ID (GEN_OBJEKT_ID, 1);
END
^

COMMIT WORK ^
SET TERM ;^

/* Grant Roles for this database */


/* Grant permissions for this database */


In Delphi habe ich dann zwei IBDataSets und zwei Grids zum Testen benutzt. Im IBDataSet für T_Jahr habe ich folgende SQLs hinterlegt (bzw. mit dem Datenmengen-Editor angelegt).

SelectSQL:
ausblenden SQL-Anweisung
1:
2:
select * from T_JAHR 
WHERE ID_OBJEKT = :ID_OBJEKT


RefreshSQL:
ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
Select 
ID_JAHR,
ID_OBJEKT,
JAHR
from T_JAHR 
where
ID_JAHR = :ID_JAHR


InsertSQL:
ausblenden SQL-Anweisung
1:
2:
3:
4:
insert into T_JAHR
(ID_OBJEKT, JAHR)
values
(:ID_OBJEKT, :JAHR)


ModifySQL:
ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
update T_JAHR
set
ID_OBJEKT = :ID_OBJEKT,
JAHR = :JAHR
where
ID_JAHR = :OLD_ID_JAHR


DeleteSQL:
ausblenden SQL-Anweisung
1:
2:
3:
delete from T_JAHR
where
ID_JAHR = :OLD_ID_JAHR



Das Ganze funktioniert auch eigentlich ganz prima, was den SELECT-Bereich angeht. Sobald ich im Objekt-Grid einen Datensatz auswähle, werden auch im Jahr-Grid nur die entsprechenden Datensätze angezeigt.

Was jedoch noch nicht läuft, ist die Anlage eines Datensatzes. Hier sollte das Feld ID_OBJEKT eigentlich mit der ID_OBJEKT von T_OBJEKT automatisch belegt werden. Zumindest klappte das mit der BDE so immer.

DataSource von der TIBDataSet der T_JAHR steht auch auf die DataSource, die mit TIBDataSet von T_OBJEKT verbunden ist.

Vielleicht hat jemand eine Idee, wie man dieses Problem in den Griff bekommt.

Vielen Dank schon mal im Voraus.

Viele Grüße
Christoph
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mo 24.09.07 01:35 
Ich glaube, ich sehs. Trotz IBOconsole. :lol:

user profile iconCBRABO hat folgendes geschrieben:
CREATE TABLE "T_JAHR"
(
"ID_JAHR" INTID NOT NULL,
"ID_OBJEKT" INTID NOT NULL,
"JAHR" INTJAHR ,
CONSTRAINT "PK_T_JAHRE" PRIMARY KEY ("ID_JAHR")
);

CREATE TABLE "T_OBJEKT"
(
"ID_OBJEKT" INTID NOT NULL,
"STRASSE" STR50 ,
"PLZ" STR10 ,
"ORT" STR50 ,
"INDABRTEXT" STR250 ,
"BEMERKUNG" STR250 ,
CONSTRAINT "PK_T_OBJEKT" PRIMARY KEY ("ID_OBJEKT")
);



Die Objekte sollen beliebig viele Jahre referenzieren können, oder wie ? Und wo bitte sehr ist die Referenz, die das Objekt für die Table Jahr braucht ? :shock: Das Jahr hat zwar ein ID_OBJEKT, aber das ist verkehrt rum gedacht. So wie es da steht, hat jedes Jahr einige Objekte. Die Objekte haben aber nicht mehrere Jahre. Von Foreign Keys sehe ich gar nichts. :gruebel:

Allgemein fällt mir aber noch folgendes auf : der SQL-Quelltext lehnt sich zu sehr an Delphi an. Das fängt mit dem Prefix T_ schon an. Das Ganze hat mit Typen in Delphi nichts zu tun. Dafür werden aber quasi-Typen (Domains) deklariert. Gefährliche Sache ! Sofern Parameter gebraucht werden und das wird nicht ausbleiben, dann hauen die dir die DB um die Ohren. Stored Procedures usw., die können nichts damit anfangen. Zuerst müssen die Tabellenstrukturen stimmen, aber zu 100 % !

Für BDE-Umsteiger würde ich außerdem dringend empfehlen, ein anständiges Admin-Tool wie IBExpert zu verwenden und keines, das noch "" überall braucht. Das ist ja ätzend. :mrgreen:

_________________
Gruß
Hansa
CBRABO Threadstarter
Hält's aus hier
Beiträge: 10

WinXP
Delphi 2007 pro
BeitragVerfasst: Mo 24.09.07 09:52 
Hallo Hansa!

Vielen Dank für Deine Antwort.

Sorry, den Foreign hatte ich nicht mitgepostet, aber schon angelegt.

Hier nochmal das gesamte SQL-Skript :

ausblenden volle Höhe SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
SET SQL DIALECT 3;

/* CREATE DATABASE 'NK2007.fdb' PAGE_SIZE 4096

 DEFAULT CHARACTER SET NONE */

/* Domain definitions */
CREATE DOMAIN "BOOL" AS SMALLINT
   CHECK ((VALUE = 0) OR (VALUE = 1));
CREATE DOMAIN "DECIMALANTEILE" AS DECIMAL(9, 4);
CREATE DOMAIN "EURO" AS DECIMAL(9, 2);
CREATE DOMAIN "FLOATQM" AS FLOAT
   CHECK (VALUE >= 0);
CREATE DOMAIN "INTID" AS INTEGER;
CREATE DOMAIN "INTJAHR" AS INTEGER
   CHECK ((VALUE >= 1900) AND (VALUE <= 2099));
CREATE DOMAIN "INTSORT" AS INTEGER;
CREATE DOMAIN "SMALLINT" AS SMALLINT;
CREATE DOMAIN "STR10" AS VARCHAR(10);
CREATE DOMAIN "STR100" AS VARCHAR(100);
CREATE DOMAIN "STR20" AS VARCHAR(20);
CREATE DOMAIN "STR250" AS VARCHAR(250);
CREATE DOMAIN "STR30" AS VARCHAR(30);
CREATE DOMAIN "STR50" AS VARCHAR(50);

/* Table: T_JAHR, Owner: SYSDBA */

CREATE TABLE "T_JAHR" 
(
  "ID_JAHR"   INTID  NOT NULL,
  "ID_OBJEKT"   INTID  NOT NULL,
  "JAHR"   INTJAHR ,
CONSTRAINT "PK_T_JAHRE" PRIMARY KEY ("ID_JAHR")
);

/* Table: T_OBJEKT, Owner: SYSDBA */

CREATE TABLE "T_OBJEKT" 
(
  "ID_OBJEKT"   INTID  NOT NULL,
  "STRASSE"   STR50 ,
  "PLZ"   STR10 ,
  "ORT"   STR50 ,
  "INDABRTEXT"   STR250 ,
  "BEMERKUNG"   STR250 ,
CONSTRAINT "PK_T_OBJEKT" PRIMARY KEY ("ID_OBJEKT")
);

/*  Index definitions for all user tables */

CREATE INDEX "IDX_T_OBJEKT_STRASSE" ON "T_OBJEKT"("STRASSE");
ALTER TABLE "T_JAHR" ADD CONSTRAINT "FK_T_JAHR_OBJEKT" FOREIGN KEY ("ID_OBJEKT") REFERENCES "T_OBJEKT" ("ID_OBJEKT") ON UPDATE CASCADE ON DELETE CASCADE;

CREATE GENERATOR "GEN_JAHR_ID";
CREATE GENERATOR "GEN_OBJEKT_ID";
SET TERM ^ ;


/* Triggers only will work for SQL triggers */

CREATE TRIGGER "TRIG_JAHR_ID" FOR "T_JAHR" 
ACTIVE BEFORE INSERT POSITION 0
as
BEGIN
  NEW.ID_JAHR = GEN_ID (GEN_JAHR_ID, 1);
END
 ^

CREATE TRIGGER "TRIG_OBJEKT_ID" FOR "T_OBJEKT" 
ACTIVE BEFORE INSERT POSITION 0
as
BEGIN
  NEW.ID_OBJEKT = GEN_ID (GEN_OBJEKT_ID, 1);
END
 ^

COMMIT WORK ^
SET TERM ;^

/* Grant Roles for this database */


/* Grant permissions for this database */


Mit den "" gebe ich Dir völlig Recht. Das war auch gleich die erste Hürde. Ich kannte das von SQL nicht und wenn man dann beim Anlegen des Triggers ständig zu hören bekommt, es gäbe kein Feld ID, obwohl man es angelegt hat (nur leider unter "id"), dann könnte man schon mal in die Tastatur beißen.

Mit den Domains wollte ich eigentlich erreichen, dass ich nachher keine Probleme habe. Denn, so dachte ich, wäre gewährleistet, dass die Typen auf jeden Fall gleich sind, wenn ich Parameter und Stored Procedures einsetze. Ich hatte einiges in der Anwendung implementiert, was auf jeden Fall mit Stored Procedures deutlich einfach zu gehen scheint. Aber wer aus der BDE-Welt kommt, macht es sich wohl ohnehin gern mal etwas komplizierter. Aber man muss dann einfach mal seinen Mut zusammen nehmen und auf eine richtige Lösung setzen oder so wie ich einfach mal richtig auf die Nase fliegen mit der BDE... :)

Eigentlich stört mich etwas, dass ich die ID in der Tabelle mit den Objekten als ID_OBJEKT und in der Tabelle mit den Jahren auch als ID_OBJEKT bezeichnen muss. Habe das im Forum gelesen, dass es sonst mit der TDataSet in Verbindung mit einer Master-Detail nicht klappen würde, wenn das referenzierte Feld nicht die gleiche Bezeichnung hat. Das wird bei den JOINS doch irgendwie ein ziemliches Durcheinander, würde ich sagen.

Ich hatte gestern auch noch mal ein Wenig probiert und einfach mal in der AfterInsert der Detail-TDataSet den Wert einfach "manuell" für ID_OBJEKT gesetzt. Das funktioniert zwar, scheint mir aber eher gebastelt als eine wirkliche Lösung zu sein.

Viele Grüße
Christoph
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mo 24.09.07 14:37 
user profile iconCBRABO hat folgendes geschrieben:
Mit den Domains wollte ich eigentlich erreichen, dass ich nachher keine Probleme habe...was auf jeden Fall mit Stored Procedures deutlich einfach zu gehen scheint...


Du musst die Antworten auch lesen. Domains und SPs geht nicht !

_________________
Gruß
Hansa
mkinzler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Mo 24.09.07 15:08 
Zitat:
Du musst die Antworten auch lesen. Domains und noch SPs geht nicht !

_________________
Markus Kinzler.
CBRABO Threadstarter
Hält's aus hier
Beiträge: 10

WinXP
Delphi 2007 pro
BeitragVerfasst: Mo 24.09.07 20:25 
Doch, gelesen habe ich Deine Antwort und auch vielen Dank für den wichtigen Hinweis.

Du hast mich aber offensichtlich falsch verstanden. Ich meinte damit, dass ich genau diese Probleme mit den Domains vermeiden wollte, als ich die DB angelegt habe. Ich habe aber doch erst durch Deinen Hinweis erfahren, dass das genau falsch herum gedacht war und mir mehr Probleme macht als es löst. Da hatten wir irgendwie aneinander vorbei geredet.

Habe mir eben mal der IBExpert als Personal Edition runtergeladen und werde es gleich mal ausprobieren.

Hast Du denn eine Idee, ob man das mit der IBDataSet auch anders lösen kann, als manuell per AfterInsert das referenzierte Feld zu setzen. Es läuft zwar so. Das scheint mir aber irgendwie unsauber zu sein. Mit dem Select und dem kaskadierten Löschen funktioniert übrigens einwandfrei, so wie es sein soll.
mkinzler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Mo 24.09.07 20:31 
Ab FireBird 2.1 kann man Domains innerhalb SP verwenden.

_________________
Markus Kinzler.
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Mo 24.09.07 20:35 
Schaffe zuerst die "" weg. Lege mit IBExpert die DB neu an. Dialect 3 einstellen ! Und dann damit testen. Sollte das gehen, dann erst mit Delphi das Programm realisieren.

@gelber Kasten : FB 2.1 sollte ziemlich egal sein. Es wurde gesagt : IBX. Also besser vergessen. 8) FB 2.1 ist noch nicht stabil.

_________________
Gruß
Hansa
mkinzler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Mo 24.09.07 20:44 
Zitat:
8) FB 2.1 ist noch nicht stabil.
Meiner Erfahrung nach schon.

_________________
Markus Kinzler.
CBRABO Threadstarter
Hält's aus hier
Beiträge: 10

WinXP
Delphi 2007 pro
BeitragVerfasst: Di 25.09.07 20:34 
IBExpert ist echt super. Klasse ist auch, dass es allein Trigger und Generatoren anlegt. Das spart wirklich ne Menge Zeit.

Leider funktioniert es mit der Master-Detail aber immer noch nicht.

Die Meta-Daten sehen aber etwas "aufgeräumter" aus:

ausblenden volle Höhe SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
/******************************************************************************/
/****         Generated by IBExpert 2007.07.20 25.09.2007 20:28:50         ****/
/******************************************************************************/

SET SQL DIALECT 3;

SET NAMES NONE;

CREATE DATABASE 'D:\RAD Studio\Projekte\NK_FireBird_DB\NK2007.FDB'
USER 'SYSDBA' PASSWORD 'masterkey'
PAGE_SIZE 16384
DEFAULT CHARACTER SET NONE;



/******************************************************************************/
/****                              Generators                              ****/
/******************************************************************************/

CREATE GENERATOR GEN_JAHR_ID;
SET GENERATOR GEN_JAHR_ID TO 6;

CREATE GENERATOR GEN_OBJEKT_ID;
SET GENERATOR GEN_OBJEKT_ID TO 3;



/******************************************************************************/
/****                                Tables                                ****/
/******************************************************************************/



CREATE TABLE JAHR (
    ID         INTEGER NOT NULL,
    OBJEKT_ID  INTEGER NOT NULL,
    JAHR       INTEGER NOT NULL
);


CREATE TABLE OBJEKT (
    OBJEKT_ID   INTEGER NOT NULL,
    STRASSE     VARCHAR(30),
    PLZ         VARCHAR(10),
    ORT         VARCHAR(20),
    INDABRTEXT  VARCHAR(250),
    BEMERKUNG   VARCHAR(250)
);




/* Check constraints definition */

ALTER TABLE JAHR ADD CHECK ((JAHR >= 1900) AND (JAHR <= 2099));


/******************************************************************************/
/****                             Primary Keys                             ****/
/******************************************************************************/

ALTER TABLE JAHR ADD CONSTRAINT PK_JAHR PRIMARY KEY (ID);
ALTER TABLE OBJEKT ADD CONSTRAINT PK_OBJEKT PRIMARY KEY (OBJEKT_ID);


/******************************************************************************/
/****                             Foreign Keys                             ****/
/******************************************************************************/

ALTER TABLE JAHR ADD CONSTRAINT FK_JAHR_OBJEKT FOREIGN KEY (OBJEKT_ID) REFERENCES OBJEKT (OBJEKT_ID) ON DELETE CASCADE ON UPDATE CASCADE;


/******************************************************************************/
/****                               Indices                                ****/
/******************************************************************************/

CREATE INDEX JAHR_IDX_JAHR ON JAHR (OBJEKT_ID, JAHR);
CREATE INDEX OBJEKT_IDX_STRASSE ON OBJEKT (STRASSE);


/******************************************************************************/
/****                               Triggers                               ****/
/******************************************************************************/


SET TERM ^ ;


/******************************************************************************/
/****                         Triggers for tables                          ****/
/******************************************************************************/



/* Trigger: JAHR_BI */
CREATE TRIGGER JAHR_BI FOR JAHR
ACTIVE BEFORE INSERT POSITION 0
as
begin
  if (new.id is null) then
    new.id = gen_id(gen_jahr_id,1);
end
^


/* Trigger: OBJEKT_BI */
CREATE TRIGGER OBJEKT_BI FOR OBJEKT
ACTIVE BEFORE INSERT POSITION 0
as
begin
  if (new.objekt_id is null) then
    new.objekt_id = gen_id(gen_objekt_id,1);
end
^


SET TERM ; ^


Oder ist das so richtig, dass man den Wert im referenzierten Feld OBJEKT_ID (in der Tabelle JAHR) in AfterInsert "manuell" belegen muss?
hansa
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 3079
Erhaltene Danke: 9



BeitragVerfasst: Di 25.09.07 22:10 
Aha. Echt brav. :lol: Trotzdem : der zweite Schritt soll anscheinend immer noch vor dem ersten gemacht werden. Die Domains sind weg, die "", dafür ist ein "Check" drin. NOT NULL würde ich auch vorsichtig verwenden. Reduziere das Ganze doch auf das absolute Minimum und baue dann langsam alles ein und nicht umgekehrt.

Am wichtigsten : wo ist die ID_JAHR in dem ID_Objekt ?? Meiner bescheidenen Meinung nach muss die Tabellenstruktur so ungefähr aussehen :

ausblenden SQL-Anweisung
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
CREATE TABLE JAHR (  
    ID         INTEGER NOT NULL,  
    ID_OBJEKT  INTEGER NOT NULL,  
    JAHR       INTEGER NOT NULL  
);  

 

 
CREATE TABLE OBJEKT (  
    ID   INTEGER NOT NULL,  
    ID_OBJEKT INTEGER,
    STRASSE     VARCHAR(30),  
    PLZ         VARCHAR(10),  
    ORT         VARCHAR(20),  
    INDABRTEXT  VARCHAR(250),  
    BEMERKUNG   VARCHAR(250)  
);

_________________
Gruß
Hansa