Entwickler-Ecke

Datenbanken - Typumwandlung bei Interbase


hansa - Do 03.10.02 12:00
Titel: Typumwandlung bei Interbase
Hallo,

habe hier folgendes Problem :

Ich muß ältere Datenbestände, die nur als Textdatei vorliegen in eine IB-DB reinkriegen. Hierzu habe ich mir eine EXTERNQAL TABLE angelegt, in der ist auch schön alles zu sehen.

Jetzt will ich diese in eine "richtige" DB per insert einfügen. Entsprechende Generatoren und Trigger sind auch vorhanden. Der Haken ist aber jetzt folgender : In der DB ist z.B. Nr. vom Typ integer, aber in der EXTERNAL TABLE char (5). Was nu ?

Außerdem finde ich nirgendwo die richtige Syntax von INSERT INTO ... FROM EXTERNAL blabla. Wie muß man das genau schreiben ?

Gruß
Hansa


LCS - Fr 04.10.02 07:31
Titel: Re: Typumwandlung bei Interbase
Hi Hansa
hansa hat folgendes geschrieben:
In der DB ist z.B. Nr. vom Typ integer, aber in der EXTERNAL TABLE char (5). Was nu ?

Geht so:

Quelltext
1:
 cast( Spaltenname as integer )                    

hansa hat folgendes geschrieben:

Außerdem finde ich nirgendwo die richtige Syntax von INSERT INTO ... FROM EXTERNAL blabla. Wie muß man das genau schreiben ?

Das hör ich zum ersten Mal :?!?: Das Schlüsselwort External kenn ich nur im Zusammenhang mit User Defined Functions.

Gruss Lothar


Udontknow - Fr 04.10.02 10:01

IB macht doch eine automatische Konvertierung, wenn man einen Textwert in ein Integerwert packen will, oder vertue ich mich da jetzt? :roll:


hansa - Fr 04.10.02 17:47

Hallo,

LCS :
Zitat:
Das Schlüsselwort External kenn ich nur im Zusammenhang mit User Defined Functions


Das war auch zuviel des guten. Mit Create Table weiß Interbase ja schon von dieser Table:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
CREATE TABLE D EXTERNAL 'D:\5.0\KUSQL' (
    NR       CHAR(5) NOT NULL,
    ANREDE   STR30,
    NAME     STR30 NOT NULL,
    STRASSE  STR30,
    ORT      STR30,
    CRLF     CHAR(2)
);


So sieht der Code vorerst aus und er funktioniert auch. :D

Jetzt ist nur noch die Frage, wie ich die Daten aus der externen Table D in die richtige IB-Table kunde reinkriege. Mein Problem liegt darin, daß ich nicht weiß, wie ich ihm sage, daß er die Daten aus der externen Datei lesen soll.

Dann taucht das nächste Problem schon auf : die kunde - Table hat noch ID's von anderen Dateien (Im Moment müßte ich die auch importieren). Wie kriege ich die ID (also den Primary-Key) einer anderen Stammtabelle in diese Datei? Es bleibt wohl nichts anderes übrig, als mit einem anderen Kriterium z.B. Nr. des Stammsatzes den entsprechenden Satz zu lesen und die Ursprungs-ID an die Datei, die ihn braucht weiterzureichen. Oje, versteht das jemand ? :autsch:

Gruß
Hansa


LCS - Mo 07.10.02 08:10

Hi
hansa hat folgendes geschrieben:
Oje, versteht das jemand ? :autsch:

Ne, net so recht am Montagmorgen :mrgreen:

Gruss Lothar


hansa - Mo 07.10.02 11:36

Hi Lothar,


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
CREATE TABLE KUNDE8 (
    ID              INTEGER NOT NULL,
    IDKGH           INTEGER,
    IDKGU           INTEGER,
    NR              INTEGER NOT NULL,
    ANREDE          STR30,
    NAME            STR30 NOT NULL,
    STRASSE         STR30,
    ORT             STR30,
    LIEFANREDE      STR30,
    LIEFNAME        STR30,
    LIEFSTRASSE     STR30,
    LIEFORT         STR30,
    TELEFON         STR25,
    TELEFONVERSAND  STR25,
    FAX             STR25,
    EMAIL           CHAR(50) CHARACTER SET ASCII
);


So sieht die IB-Tabelle kunde8 aus, die externe Tabelle D steht ja weiter oben. Schau dir mal in beiden Fällen das Feld Nr. an. In der alten Datei steht es halt als char drin und das soll in IB ein integer werden. Das geht so :


Quelltext
1:
select CAST (nr AS integer), name, strasse, ort FROM D;                    


In der Ergebnismenge steht dann auch das gewünschte.

Lasse ich aber jetzt folgendes ablaufen :

Quelltext
1:
INSERT INTO kunde8 SELECT CAST (nr AS integer),anrede,name,strasse,ort from D                    


Das CAST ist also die Typumwandlung ! Das hab ich nun geschnallt. Aber bei obigem INSERT kommt die Fehlermeldung:

"Count of read write columns not equal count of values"

Da steht auch wieder ein SELECT drin. Das erste Select klappt ja, aber wo steckt denn eigentlich diese Ergebnismenge überhaupt ? Gebe ich nur ein

INSERT INTO kunde8

kommt "unexpected end of command". Das krieg ich einfach nicht hin. Habe alles mögliche probiert.

Nochmals zu den IDs : Es geht darum, die ID, der einem Kunden zugeordneten Kundengruppe als IDKGH (das ist die entsprechende Fremd-ID der Kunden-Hauptgrupe für einen Kunden) richtig in die Kunden-Table reinzukriegen. Oder so : IDKGH (in Kunde-DS, kein Primary) ist gleich der ID der Kundengruppe (Primary), d.h. der Verweis im Kunde-DS auf die ihm zugeordnete Kundenhauptgruppe. Uff.

Gruß
Hansa


LCS - Mo 07.10.02 11:53

Hi
Die Anweisung

Quelltext
1:
INSERT INTO kunde8 SELECT CAST (nr AS integer),anrede,name,strasse,ort from D                    

liefert dir ja nur 5 Felder. Deine Tabelle Kunde8 hat aber wesentlich mehr. Also beschwert sich IB. Du musst angeben welche Felder der Tabelle mit diesen Werten gefüllt werden sollen:

Quelltext
1:
INSERT INTO kunde8 (NR, ANREDE, NAME, STRASSE, ORT) ....                    

Damit stimmt die Anzahl der einzufügenden Werte mit der Anzahl der Spalten des Select überein.
Das nächste Problem kriegst du allerdings wenn du bei dieser Aktion nicht allen Feldern mit not Null einen Wert zuweist, oder generierst.

Bei deinen IDs versteh ich das Problem immer noch nicht so ganz. Wenn diese Gruppen IDs in den zu übernehmenden Daten auch schon vergeben waren, müssen sie in der neuen Tabelle identisch übernommen werden. Das muss aber vorher passieren, weil du ja in der Kundentabelle darauf Bezug nimmst.

Gruss Lothar


hansa - Mo 07.10.02 12:34

Hi,

die Klammern hinter Insert "into kunde8 (...", ja das müßte es sein, nein das kann es nur sein. Übernehme ich so ungetestet, muß gleich weg. War selber nah dran, aber ??? Irgendwo hängt man dann fest wegen sowas. :mrgreen:

Zitat:
. Wenn diese Gruppen IDs in den zu übernehmenden Daten auch schon vergeben waren, müssen sie in der neuen Tabelle identisch übernommen werden. Das muss aber vorher passieren, weil du ja in der Kundentabelle darauf Bezug nimmst


Moment mal, gaaaanz langsam. In der DB sind Generatoren vorhanden, um die IDs zu vergeben. Übernehme ich die alten IDs 1:1 müßte ich diese abschalten. Bei der Übernahme aus der externen table handelt es sich ja nur um eine einmalige Aktion. Später müsen neue IDs vergeben werden. Also brauche ich die Generatoren doch.

Gruß
Hansa


LCS - Mo 07.10.02 12:51

Hi
hansa hat folgendes geschrieben:

In der DB sind Generatoren vorhanden, um die IDs zu vergeben.

Genau das ist das Problem. Du willst bei der Datenübernahme die IDs neu vergeben und müsstest dabei auch alle referentiellen Integritäten abchecken. In der alten Tabelle sind die aber schon abgecheckt (hoffentlich).
hansa hat folgendes geschrieben:

Übernehme ich die alten IDs 1:1 müßte ich diese abschalten.

Genauso isses :!:
hansa hat folgendes geschrieben:

Bei der Übernahme aus der externen table handelt es sich ja nur um eine einmalige Aktion. Später müsen neue IDs vergeben werden. Also brauche ich die Generatoren doch.

Wenn alle Daten übernommen sind, bekommen die Generatoren als Startwert die höchste übernommene ID zugewiesen und werden wieder aktiviert.
Damit sind die alten Daten 1:1 übernommen und neue Werte werden von dem Moment an automatisch erzeugt.
Damit umgehst du automatisch auch den Ärger mit den Anwendern, wenn die ID 17 in der neuen Tabelle auf einmal die ID 9 ist. Natürlich nur sofern die IDs sichtbar sind.

Gruss Lothar


hansa - Mo 07.10.02 13:06

Hi Lothar,

Alt-ID's sind nicht sichtbar. Die Integrität stimmt (hoffe es jedenfalls auch 8) ).

Zitat:
Wenn alle Daten übernommen sind, bekommen die Generatoren als Startwert die höchste übernommene ID zugewiesen und werden wieder aktiviert.


Mensch Meier. Bin ich blöd. :oops: Manchmal braucht man wirklich jemanden, der einem auf die Sprünge hilft. :mrgreen:

Nur eines noch, wie schalte ich eigentlich die Generatoren temporär ab ??

Gruß
Hansa

jetzt aber, nix wie weg.....


LCS - Mo 07.10.02 13:12

Hi
Zitat:

Nur eines noch, wie schalte ich eigentlich die Generatoren temporär ab ??

Einfache Antwort: Geht nicht :lol:
Im Ernst: Die Generatoren selbst kannst du nicht abstellen. Die kannst du ja nicht mal so einfach löschen. Das Einzige was du abstellen kannst sind die zugehörigen Trigger.

Quelltext
1:
2:
3:
ALTER TRIGGER name INACTIVE
oder
ALTER TRIGGER name ACTIVE


Gruss Lothar


hansa - Mo 07.10.02 17:24

Hi Lothar,

ja das wars, habe jetzt ca. 1000 Kunden in der DB, aber mehr oder weniger nur mit Adresse (also die Felder aus der externen Table). Nun gut, dann knöpf ich mir die mal vor und schreibe alles rein was vorhanden ist, da taucht bestimmt noch so ein Typ-Problem auf. Ohje, da brauche ich gar nicht lange zu überlegen: Aufzählungstypen, Arrays und was es so gibt. :hair:

Gruß
Hansa

Was mich allerdings wundert, das Konvertieren aus der Textdatei ging ohne merklichen Zeitverlust, wenn man hier so liest, wie manche um Minuten kämpfen ? :mrgreen: Sogar die deutschen Umlaute sind richtig.


hansa - Mo 07.10.02 17:42

Hi,

da gehts schon los, verfügbare Bücher richten sich anscheinend nur an Leute, die sowieso alle Daten neu eingeben müssen. :lol: Wo gibts denn sowas. :bawling: Heutzutage verkäuft man nur ein Programm falls derjenige, der es gerne hätte, eben zumindest nicht ALLES selber eingeben muß. Jetzt bleibe ich schon am date hängen. Wie soll ich das denn in die Textdatei schreiben, so daß IB das versteht ? Die Aufzählungs- und Bool-Typen muß ich wohl als smallint darstellen oder nicht ?

Mir jetzt egal, wird alles vorerst ausgeklammert. :mrgreen: Ich will heute noch eine Datei haben, in der (bis auf diese Problemfälle) alles drin ist.

Gruß
Hansa


LCS - Mo 07.10.02 20:50

Hi hansa,
da wollt ich doch glatt nach deinem vorletzten Posting schon applaudieren :mrgreen:
Zitat:

Jetzt bleibe ich schon am date hängen. Wie soll ich das denn in die Textdatei schreiben, so daß IB das versteht ?

Wenn du das direkt mittels SQL einliest, sollte eigentlich das Format 'dd.mm.yyyy' in Ordnung gehen. Im Zweifelsfall kannst du aber auch mal 'mm/dd/yyyy' testen.
Zitat:

Die Aufzählungs- und Bool-Typen muß ich wohl als smallint darstellen oder nicht ?

Wird wohl das Beste sein. Bool-Typen gibts bei IB nicht.

Gruss Lothar


hansa - Di 08.10.02 21:24

Hallo,

weiß jemand, wie die boolean Typen sonstwo meistens umgesetzt werden, Smallint würde sich zwar anbieten, aber was ist mit CHAR (1) ? Wo lauern da eventuelle Fallen, bzw. was wäre besser ?

Aber noch einmal zu der Typumwandlung : :mrgreen:

Also ich habe jetzt mal eine kleinere Table als Textdatei hergestellt, sie in eine Externe IB-Table und schließlich in eine richtige befördert. Da sind IDs drin, die ich für größere brauche. Dann habe ich dasselbe mit meiner Kunden-Table gemacht. Die Felder, die ich so lassen will habe ich übernommen, die die mir nicht gefielen habe ich vorerst ausgeklammert. Die Textdatei habe ich dann genau so, wie mit der kleinen Table vorher, in eine externe IB-Table befördert. Die gewünschten Felder und vor allem die Daten waren da. :D

Dann gings weiter mit der richtigen IB-Table !!! :hair: Am Anfang waren natürlich kleine Tipfehler und sowas drin, aber nach und nach kam ich weiter.


hansa - Di 08.10.02 21:26

@Admin: der letzte Beitrag wurde urplötzlich ohne Abfrage geschickt ????

das wichtige kommt nämlich erst.


hansa - Di 08.10.02 21:38

@Admin :twisted: schon wieder ! Gibt es irgendeinen Hotkey, den man aus Versehen drücken kann?

Meine Externe Table hat ca. 60 Felder, das Erzeugen der IB-Table hat auch noch einwandfrei geklappt. Aber beim Einfügen der Daten (mit Typumwandlungen) kommt dann folgende Fehlermeldung :

Zitat:
Conversion from string " " on line
und dann das ganze insert Statement, paßt nicht auf eine Seite, für die IBconsole ist es eine einzige Zeile, wo 2mal 60 Felder aufgeführt werden. Ich sehe weder wo der Fehler ist, noch weshalb. Hat einer einen Tip parat ? Oder muß ich alles wieder neu machen ? 8) Ohne Zeilenzahl ist das ganze wie gesagt auch noch.

Gruß
Hansa


LCS - Mi 09.10.02 15:21

Hi
die Fehlerausgabe von IBConsole ist wirklich krass :shock:. Aber Conversion from String... bedeutet eigenlich ein Problem bei der Typumwandlung. Das können leere DB-Felder sein, Umlautprobleme oder sonstwas.
Ich hab bis jetzt die Erfahrung gemacht, dass es wesentlich schneller geht ein simples Programm zu schreiben, das die Daten einliest, konvertiert und dann in die neue Datenbank schreibt, als bei IBConsole und ISQL Nerven zu lassen.

Gruss Lothar


hansa - Mi 09.10.02 16:52

Hi,

Zitat:
Ich hab bis jetzt die Erfahrung gemacht, dass es wesentlich schneller geht ein simples Programm zu schreiben, das die Daten einliest, konvertiert und dann in die neue Datenbank schreibt, als bei IBConsole und ISQL Nerven zu lassen.


Wie meinst Du das ? Welches Programm soll die Daten einlesen und konvertieren ? Letztenendes muß das doch IB schaffen. Ob ich jetzt eine Textdatei habe oder eine Datendatei, die ich später in einen Text konvertiere. Wo ist da der Unterschied ?

Gruß
Hansa


LCS - Do 10.10.02 09:16

hansa hat folgendes geschrieben:
Wo ist da der Unterschied ?

Der Unterschied ist einfach der, dass du dich nicht mit den Unzulänglichkeiten und Fehlern von IBConsole rumärgern musst. :D


hansa - Do 10.10.02 12:05

Hi Lothar,

Meinst Du, ich solle DAS HIER :


Quelltext
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:
118:
119:
120:
SET SQL DIALECT 3;

SET NAMES ISO8859_1;

INSERT INTO KUNDE8  (
    ID,
    NR,
    ARKGHAUPT,
    ARKGUNTER,
    KUNDEPREISGLEICH,
    ARHAUSEIGENT,
    ARPAECHTER,
    ARSTAMMFAHRER,
    ARVERTRETER,
    ARSTAMMFAHRZEUG,
    RECTEXTNR,
    LIEFTEXTNR,
    STAMMTOUR,
    SKONTO,
    KREDITBETRAG,
    KREDITLIMIT,
    TELEFON,
    TELEFONVERSAND,
    FAX,
    MODEM,
    RUHETAG,
    ANRUFTAG,
    ANRUFZEIT,
    BLZ,
    KONTONR,
    BANK,
    ANREDE,
    NAME,
    STRASSE,
    ORT,
    LIEFANREDE,
    LIEFNAME,
    LIEFSTRASSE,
    LIEFORT,
    PREISGRUPPE,
    RECZEITRAUM,
    ABHOLER,
    ZENTRKUNDE,
    EINZPRDRUCKEN,
    BANKEINZUG,
    BRUTTOPREIS,
    PREISABFRAGE,
    LIEFERSPERRE,
    STATFUEHREN,
    KUNDESEIT,
    LETZTERBEZUG,
    KASSEVORH,
    KUARTNRDRUCKEN,
    EMAIL,
    RVZEITRAUM,
    SAMMELKUNR,
    FREMDKUNR,
    AUFAUSGLISTE,
    ZAHLBEDNR,
    DIVERS)

SELECT CAST (ID AS INTEGER),
       CAST (NR AS INTEGER),
       CAST (ARKGHAUPT AS INTEGER),
       CAST (ARKGUNTER AS INTEGER),
       CAST (KUNDEPREISGLEICH AS INTEGER),
       CAST (ARHAUSEIGENT AS INTEGER),
       CAST (ARPAECHTER AS INTEGER),
       CAST (ARSTAMMFAHRER AS INTEGER),
       CAST (ARVERTRETER AS INTEGER),
       CAST (ARSTAMMFAHRZEUG AS INTEGER),
       CAST (RECTEXTNR AS INTEGER),
       CAST (LIEFTEXTNR AS INTEGER),
       STAMMTOUR,
       CAST (SKONTO AS DECIMAL (10,2)),
       CAST (KREDITBETRAG AS DECIMAL (10,2)),
       CAST (KREDITLIMIT AS DECIMAL (10,2)),
       TELEFON,
       TELEFONVERSAND,
       FAX,
       MODEM,
       RUHETAG,
       ANRUFTAG,
       ANRUFZEIT,
       BLZ,
       KONTONR,
       BANK,
       ANREDE,
       NAME,
       STRASSE,
       ORT,
       LIEFANREDE,
       LIEFNAME,
       LIEFSTRASSE,
       LIEFORT,
       PREISGRUPPE,
       RECZEITRAUM,
       abholer,
       ZENTRKUNDE,
       EINZPRDRUCKEN,
       BANKEINZUG,
       BRUTTOPREIS,
       PREISABFRAGE,
       LIEFERSPERRE,
       STATFUEHREN,
       KUNDESEIT,
       LETZTERBEZUG,
       KASSEVORH,
       KUARTNRDRUCKEN,
       EMAIL,
       RVZEITRAUM,
       SAMMELKUNR,
       FREMDKUNR,
       AUFAUSGLISTE,
       ZAHLBEDNR,
       DIVERS

FROM KUEXP;

COMMIT;






für eine Tabelle, die so erzeugt wurde :


Quelltext
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:
SET SQL DIALECT 3;

SET NAMES ISO8859_1;

/* DROP TABLE KUNDE8; */

CREATE TABLE KUNDE8  (
    ID INTEGER NOT NULL,
    NR INTEGER NOT NULL,
    ARKGHAUPT INTEGER,
    ARKGUNTER INTEGER,
    KUNDEPREISGLEICH INTEGER,
    ARHAUSEIGENT INTEGER,
    ARPAECHTER INTEGER,
    ARSTAMMFAHRER INTEGER,
    ARVERTRETER INTEGER,
    ARSTAMMFAHRZEUG INTEGER,
    RECTEXTNR INTEGER,
    LIEFTEXTNR INTEGER,
    STAMMTOUR CHAR (8),
    SKONTO DECIMAL (10,2),
    KREDITBETRAG DECIMAL (10,2),
    KREDITLIMIT DECIMAL (10,2),
    TELEFON CHAR (20),
    TELEFONVERSAND CHAR (20),
    FAX CHAR (20),
    MODEM CHAR (20),
    RUHETAG CHAR (1),
    ANRUFTAG CHAR (1),
    ANRUFZEIT CHAR (1),
    BLZ CHAR (10),
    KONTONR CHAR (10),
    BANK CHAR (30),
    ANREDE CHAR (30),
    NAME CHAR (30) NOT NULL,
    STRASSE CHAR (30),
    ORT CHAR (30),
    LIEFANREDE CHAR (30),
    LIEFNAME CHAR (30),
    LIEFSTRASSE CHAR (30),
    LIEFORT CHAR (30),
    PREISGRUPPE CHAR (1),
    RECZEITRAUM CHAR (1),
    ABHOLER CHAR (1),
    ZENTRKUNDE CHAR (1),
    EINZPRDRUCKEN CHAR (1),
    BANKEINZUG   CHAR (1),
    BRUTTOPREIS  CHAR (1),
    PREISABFRAGE CHAR (1),
    LIEFERSPERRE CHAR (1),
    STATFUEHREN CHAR (1),
    KUNDESEIT CHAR (10),
    LETZTERBEZUG CHAR (10),
    KASSEVORH CHAR (1),
    KUARTNRDRUCKEN CHAR (1),
    EMAIL CHAR (30),
    RVZEITRAUM CHAR (1),
    SAMMELKUNR CHAR (1),
    FREMDKUNR CHAR (10),
    AUFAUSGLISTE CHAR (1),
    ZAHLBEDNR CHAR (3),
    DIVERS CHAR (1));

COMMIT;



mit Delphi-Befehlen machen ? :hair: Ja wie denn ? Vielleicht macht sich ja jemand die Mühe, druckt das aus und sieht den Fehler sofort. :mrgreen: Nein, aber im Ernst : Vermute stark, Du meinst ich solle die externe Table vergessen, die IBconsole auch und direkt in Delphi die Felder aus der Textdatei fischen und direkt in die DB schreiben ?

Wie gesagt ich weiß nicht, ob Du das so meinst und wenn doch, dann habe ich nämlich folgende Bedenken :

1. Wenn ich diese Statements als einen SQL-string behandele, so wird das wohl wiederum eine nichtssagende Fehlermeldung bringen.

2. Wenn ich die Felder einzeln in die DB reinhaue ist das ein Haufen Mehrarbeit. Letztenendes würde wahrscheinlich wiederum erst an der Stelle, an der das Commit durchgeführt wird der Fehler auftauchen. Außerdem wäre da wieder die Frage mit der Typumwandlung.

3. Dann bliebe als Ausweg, nach jedem Feld ein post (? oder womit wird ein Commit ausgelöst ?) durchzuführen, um das Feld zu erwischen, das den Ärger macht: noch aufwendiger.

Wegen solcher und ähnlicher Geschichten wollte ich ja gerade eine kleine Table (Kundengruppen) und eine größere, die die kleinere als Lookup usw. braucht. Wie übergebe ich denn überhaupt direkt mit Delphi einen Teilstring als richtigen Typ an IB ?

Wo ich das hier schreibe, denke ich Methode 3. ist das einzig vernünftige. Denn ist die Fehlerquelle lokalisiert, könnte man das Script entsprechend anpassen und ab dann doch verwenden.

Das sind aber zu viele offene Fragen, bin deshalb im Moment zu unsicher, ob das so überhaupt stimmt / geht. 8)

Gruß
Hansa


LCS - Do 10.10.02 12:36

Hi
Hansa hat folgendes geschrieben:

mit Delphi-Befehlen machen ? Ja wie denn ?

Genau das mein ich.

Zitat:

Wenn ich die Felder einzeln in die DB reinhaue ist das ein Haufen Mehrarbeit.

table.Fields[x].Value := ....
Ob ich das nun einmal hinschreibe oder 50x kopiere spielt eigentlich keine grossen Rolle.

Zitat:

Außerdem wäre da wieder die Frage mit der Typumwandlung.

Fields[x].AsString
Fields[x].AsInteger
Fields[x].AsDateTime usw.
Wo ist hier das Problem :?!?:
Wenn der Datentyp nicht passt, kriegst du hier an dieser Stelle schon die passende Exception die du abfangen kannst. Methode 3 ist demnach unnötig.

Da die Datenübernahme sowieso nur einmal gemacht wird, spielt der Zeitbedarf auch nicht die grosse Rolle, also kannst du hier auch ohne Probleme IBTable verwenden. Das macht das Leben ein bisschen angenehmer und der Performanceverlust ist an dieser Stelle egal.

Der Hauptgrund für mich war aber folgender: Die Problematik mit Datenübernahme und Konvertierung aus Text oder unterschiedlichen Tabellen taucht immer wieder auf. Und die daraus resultierenden Probleme mit SQL und IBConsole auch.
Also setze ich mich doch lieber einmal hin und schreibe ein vernünftiges Programm mit dem sich sowas flexibel handhaben lässt und hab dann ein für allemal Ruhe. 8)

Gruss Lothar
*derdasallesschonhintersichhat*


hansa - Do 10.10.02 13:40

Zitat:
*derdasallesschonhintersichhat*

:autsch: -> :bawling: -> :shock: -> :think: -> :mrgreen:


LCS - Do 10.10.02 14:04

Treffender kann mans kaum beschreiben :lol:


hansa - Fr 11.10.02 12:09

Hi,

Sehe das mittlerwiele genauso. Plage mich nicht mehr mit so ner Mist(IB)Console rum.

Zitat:
Da die Datenübernahme sowieso nur einmal gemacht wird, spielt der Zeitbedarf auch nicht die grosse Rolle, also kannst du hier auch ohne Probleme IBTable verwenden. Das macht das Leben ein bisschen angenehmer und der Performanceverlust ist an dieser Stelle egal.


Mit der IBtable habe ich aber ein Problem. Seltsamerweise habe ich die noch nie gebraucht. :?: Eigentlich alles unter dem Register Interbase hab ich noch nicht gebraucht. Auf jeden Fall sagt er mir, egal was ich mache Database not assigned, invalid property oder so was. Für mich sieht es so aus, als sei die IBtable ein Fremdkörper.

Gruß
Hansa


LCS - Fr 11.10.02 13:03

Hi
ich hab das IBTable nur stellvertretend für eine Tabellenkomponente gemeint, weil ich die in dem Fall verwende. Zu IBTable gehört dann natürlich auch eine IBDatabase und eine IBTransaction.
Wenn du mit FIB (oder wie auch immer die Dinger heissen :wink: ) arbeitest, musst du dir aus diesen Komponenten halt das passende raussuchen.

Gruss Lothar
x - 117 min


hansa - Sa 12.10.02 12:37

Hi,

was ich jetzt habe, sowas mußte ja kommen. :angel:


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
procedure TForm1.Button1Click(Sender: TObject);

VAR k : text;
    zeile : string;
begin
  assign (k,'KGSQL');
  reset (k);
  WHILE NOT EOF (k) DO BEGIN
    readln (k);
    KGdatensatz.insert;
    KGdatensatz.ID := AsInteger
  END;
end;


Wie man sieht, wollte ich mit einfachen Standard-Pascal Mitteln Zeile für Zeile aus der Textdatei lesen und in die DB schreiben. Aber erstens kommt es anders und zweitens, als man denkt. :mahn: Delphi kennt den Typ text so nicht mehr. Ohne es zu merken habe ich anscheinend diesen Typ schon länger nicht mehr gebraucht. Weiterhin steht irgendwo, man müsse eine Konsolenapplikation haben. Für den gewünschten Zweck brauche ich ja auch keine eigene Benutzeroberfläche, aber was ist dann mit meinen Komponenten auf der Form ? Einen Ersatz für text hab ich bisher nicht gefunden.

Gruß
Hansa


hansa - So 13.10.02 12:34

Hi,

text -> TextFile
assign -> AssignFile

soviel zu dem letzten. Jetzt ist aber noch eine Frage aufgetaucht :

Zitat:
table.Fields[x].Value := ....


Worauf bezieht sich eigentlich das x ? Muß ich da etwa die Reihenfolge der Felder aus der IB-DB einhalten ? Kann man die Zuweisung nicht ungefähr so machen ?


Quelltext
1:
KGdatensatz.Fields.ID := StrToInt (copy (zeile,1,10));                    


Also den Namen des IB-Feldes direkt ansprechen ? Das wäre eine Fehlerquelle weniger. :wink2:

Gruß
Hansa


hansa - So 13.10.02 17:47

Hey,

macht hier alles Urlaub, nur ich nicht ? :P Dauert zwar länger, als wenn mir jemand hilft, aber in seltenen Fällen nützt sogar die OH.
Zitat:
withClientDataSet1 do

begin
{ This is the safe way to change 'CustNo' field }
FindField('CustNo').AsString := '1234';
{ This is *not* the safe way to change 'CustNo' field }
Fields[0].AsString := '1234';

end;


Der Array-Index würde irgendwann Ärger machen. Da bin ich mir sicher (simple Tippfehler usw.). Nun denn, weiter gehts. :mrgreen:

Gruß
Hansa


hansa - So 13.10.02 18:19

Hi,


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure TForm1.Button1Click(Sender: TObject);
VAR k : textfile;
    zeile : string;
begin
  AssignFile (k,'D:\8.0\KGSQL');
  reset (k);
  WHILE NOT EOF (k) DO BEGIN
    readln (k,zeile);
    KGdatenSatz.insert;
    showmessage ('*' + zeile + '*');
    KGdatenSatz.FindField('ID').AsInteger := StrToInt (copy (zeile,1,10));
    KGdatenSatz.FindField('NR').AsString := copy (zeile,11,15);
    KGdatenSatz.FindField('BEZ').AsString := copy (zeile,16,40);
  END;
end;

Soweit sieht das schon mal gut aus. ABER : :idea: Irgendwo fehlt doch noch was. Die Felder ID und NR sind integer. BEZ ist in IB char (25). In der Textdatei hat ID Länge 10 und nr 5. Kriege aber immer die Beschwerde, nr könne nicht richtig umgewandelt werden. BEZ ist ja sowieso ein string. Das mit AsInteger usw. hab ich ansch. noch nicht kapiert.

Gruß
Hansa
[/quote]


hansa - So 13.10.02 19:20

So gehts halt doch (mit der kleinsten Datei, die mir einfiel) :mrgreen: :
Kopiert man einen Teilstring jedesmal aus einem kompletten und beginnt bei Zeichen 1, so kann es nicht gehen. 8)


Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure TForm1.Button1Click(Sender: TObject);
VAR k : textfile;
    zeile : string;
begin
  AssignFile (k,'D:\8.0\KGSQL');
  reset (k);
  KGdatenSatz.open;
  WHILE NOT EOF (k) DO BEGIN
    readln (k,zeile);
    KGdatenSatz.insert;
    KGdatenSatz.FindField('ID').AsInteger := StrToInt (copy (zeile,1,10));
    KGdatenSatz.FindField('NR').AsString := copy (zeile,11,5);
    KGdatenSatz.FindField('BEZ').AsString := copy (zeile,16,25);
    KGdatenSatz.Post;
  END;
  CloseFile (k);
  DataBase.Commit;
end;

Lasse ich das aber zweimal ablaufen, ist alles doppelt in der DB... also können die Indices nicht stimmen....kein Wunder, da ich die ganze DB gelöscht habe. :angel: ..stimmen die Generatoren und Trigger überhaupt ? :dance2: :dance: :nut:

Gruß
Hansa


hansa - Mi 16.10.02 21:33

Hi,

jetzt ist noch ein Problem aufgetaucht. 8) Bei den umzuwandelnden Daten habe ich auch Date und Time-Felder. Die Date-Felder hab ich so behandelt :

Quelltext
1:
KUdatenSatz.FindField('KUNDESEIT').AsDateTime := StrToDate (copy (zeile,537,10));                    


Ich schnapp mir also einen Teilstring der Länge 10 und übergeb ihn dem IB-Datensatz. Ist dieser Teilstring z.B.'01.11.2001' steht danach in der DB '01.11.01'. Tag und Monat stehen also in der richtigen Reihenfolge drin, das Jahr ist aber nur 2-stellig. Der Punkt als Datums-Separator scheint ja zu gehen. Das DB - Feld ist aber als char (10) hinterlegt, irgendwo wird trotzdem das Jahr abgeschnitten.

Das mit Char (10) ist aber sowieso eine Übergangslösung, da ich außer Timestamp in IB noch nichts gesehen habe. Aber muß ich wirklich Date und Time-Variablen in solch eine Kiste zwängen ? Falls ja, wie geht denn das.

Jetzt fällt mir noch was auf : in obigem Code steht ja drin AsDateType und StrToDate. Also wird von Delphi der string falsch umgerechnet (zumindest für diesen Fall) oder die IB-DB macht das dann nicht, wie ich es will. Oder irgendwelche Windows-Einstellungen sind dran Schuld. Weiß jemand was ?

Gruß
Hansa


LCS - Do 17.10.02 09:39

Hi
Wenn du das Datum in einem Char-Feld speicherst ist die Zuweisung wie du sie machst unnötig.

Quelltext
1:
KUdatenSatz.FindField('KUNDESEIT').AsDateTime := StrToDate (copy (zeile,537,10));                    

Du wandelst zuerst den String in ein Datum um (dadurch entsteht auch deine zweistellige Jahreszahl), dann weist du dieses Datum mit AsDateTime einem Stringfeld zu damit es wieder in einen String umgewandelt wird.
In dem Fall würde genügen:

Quelltext
1:
KUdatenSatz.FindField('KUNDESEIT').AsString := copy (zeile,537,10);                    


hansa hat folgendes geschrieben:

Das mit Char (10) ist aber sowieso eine Übergangslösung, da ich außer Timestamp in IB noch nichts gesehen habe.

Alle anderen Datenbanken die ich kenne, verfügen auch nur über einen DatumZeit Typ. Wozu willst du noch was anderes :?!?:

hansa hat folgendes geschrieben:

Aber muß ich wirklich Date und Time-Variablen in solch eine Kiste zwängen ?

Wo ist denn dabei das Problem? In Delphi verwendest du doch auch TDateTime.
hansa hat folgendes geschrieben:

Falls ja, wie geht denn das.

Genauso wie du es in deinem Code schon machst:

Quelltext
1:
KUdatenSatz.FindField('KUNDESEIT').AsDateTime := StrToDate (copy (zeile,537,10));                    


Gruss Lothar


hansa - Do 17.10.02 11:53

Hi,

Zitat:
Alle anderen Datenbanken die ich kenne, verfügen auch nur über einen DatumZeit Typ


Wollte jetzt mal die Datum/Zeit-Felder in Ordnung bringen. Als erstes wollte ich die DB-Definition anpassen, danach das Programm.

Aber sieh an ! Ich habe ja zur Auswahl TimeStamp, sowie date und time. :hair: Was ist denn das jetzt ? Zu der zweistelligen Jahresangabe habe ich jetzt noch folgendes gefunden : DateTimeToSQLTimeStamp function. Das ist in der Unit SQLTIMST. Muß ich mir mal ansehen. Wie gesagt, bin ich davon ausgegangen, daß es nur TimeStamp gibt. Jetzt taucht date und time auf!!
Zitat:
Wozu willst du noch was anderes

Will ich ja gar nicht. Ich kann höchstens eine Ex-Freundin zitieren : "Du bist anders, als die anderen." :mrgreen:

Gruß
Hansa


LCS - Do 17.10.02 13:44

Hi
Date und Time sind die Dialect 1 Felder. Wenn du eine Dialect 3 Datenbank verwendest, solltest du Timestamp verwenden, das kompatibel mit TDateTime ist.
Wenn du eine Dialect 1 Datenbank verwendest, musst du stattdessen Date verwenden. In dem Fall ist Date kompatibel mit TDateTime und ermöglicht damit auch das Speichern von Zeitwerten.
Hat mich allerdings auch einiges an Nerven gekostet, bis ich da drauf gekommen bin. :autsch:

Gruss Lothar


hansa - Do 17.10.02 18:04

Hi Lothar,

Zitat:
Date und Time sind die Dialect 1 Felder


Danke für die Antwort. Sowas steht dann wahrscheinlich auf Seite 899 in einem Buch von 900 Seiten für 50 EUR. :mrgreen:

Gruß
Hansa


hansa - Do 17.10.02 19:37

Hi,

habe jetzt die entsprechnden Felder der DB auf TimeStamp umgebaut. In der DB stehen jetzt auch 4-stellige Jahreszahlen drin, Uhrzeit ist halt 00:00. Im Quellcode steht das ganze aber noch als TstringField. Da kommt er durcheinander. Im OI finde ich nichts über den Typ eines Feldes. Und den Quelltext, wo halt drin steht, daß es ein TstringField ist traue ich mich im Moment nicht einfach so von Hand zu verändern. Habe von 70 Feldern nur noch 5 übrig die bearbeitet werden müssen. 8) Wie mach ich denn das jetzt, ohne alles zu versauen. :mahn:

Gruß
Hansa


LCS - Fr 18.10.02 07:49

Hi
Hansa hat folgendes geschrieben:

Im Quellcode steht das ganze aber noch als TstringField. Da kommt er durcheinander. Im OI finde ich nichts über den Typ eines Feldes.

Wenn du an der Stelle persistente Felder verwendet hast, öffnest du einfach noch mal den Feldeditor, löscht das betreffende Feld und fügst es an der gleichen Position wieder neu ein. Dann passt das.

Hansa hat folgendes geschrieben:

Sowas steht dann wahrscheinlich auf Seite 899 in einem Buch von 900 Seiten für 50 EUR.

:lol: Nein, danz so krass wars nicht. Das steht irgendwo in der IB Dokumentation so zwischen den Zeilen.

Gruss Lothar


hansa - Fr 18.10.02 10:45

Hi,

wie immer hat Lothar Recht. So geht das ! 8)

Zitat:
Du löschst das betreffende Feld und fügst es an der gleichen Position wieder neu ein. Dann passt das.

Will das aber etwas präzisieren. Löschen des Feldes ist klar. Aber mit Einfügen ist gemeint die Funktion Add Field zu benutzen und NICHT new Field. Der Unterschied besteht darin, daß bei new Field Name,Typ usw. angegeben werden muß. Bei add field kriegt man eine Liste noch verfügbarer Felder, wo dann der richtige Typ gleich richtig angelegt wird.

Gruß
Hansa


hansa - Mo 28.10.02 08:39

Hi,

stecke wieder mal fest. Habe jetzt mal die Indices definiert :


Quelltext
1:
2:
3:
ALTER TABLE KUNDE8 ADD PRIMARY KEY (ID);
ALTER TABLE KUNDE8 ADD FOREIGN KEY (ARKGHAUPT) REFERENCES KG8 (ID) ON DELETE CASCADE ON UPDATE CASCADE;
ALTER TABLE KUNDE8 ADD FOREIGN KEY (ARKGUNTER) REFERENCES KG8 (ID) ON DELETE CASCADE ON UPDATE CASCADE;


Die Foreign Keys sind zwei verschiedene Keys aus einer Tabelle.

Will ich die zugehörigen Felder nun folgendermaßen in die Tabelle eintragen :


Quelltext
1:
2:
3:
4:
5:
    KuDatenSatz.insert;
    KuDatenSatz.FindField ('ID').AsInteger := StrToInt (copy (zeile,1,10));
    KuDatenSatz.FindField ('NR').AsInteger := StrToInt (copy (zeile,11,5));
    KuDatenSatz.FindField ('ARKGHAUPT').AsInteger := StrToInt (copy (zeile,16,10));
    KuDatenSatz.FindField ('ARKGUNTER').AsInteger := StrToInt (copy (zeile,26,10));


so kommt die Fehlermeldung "Access Violation" in der Zeile nach NR.

In der Tabelle steht :

Quelltext
1:
2:
3:
4:
5:
CREATE TABLE KUNDE8 (
    ID                INTEGER NOT NULL,
    NR                INTEGER NOT NULL,
    ARKGHAUPT         INTEGER,
    ARKGUNTER         INTEGER,


Weiß wer was ? :roll: In der referenzierten Table stehen keine Null Werte oder so was, die stimmt.

Gruß
Hansa


hansa - Mo 28.10.02 11:11

Hi Leute,

nichts für ungut. 8) Aber der Umgang mit dem Kram hier erfordert eine gewisse Erfahrung, ist die noch zu gering, passieren kleine Fehler, die große Auswirkungen haben. Hier waren es gleich zwei. Den ersten weiß ich nicht mehr, aber der hier war anscheinend tödlich : Hatte die BI-Trigger vergessen. :idea:

Gruß
Hansa


hansa - Do 14.11.02 01:25

Hi,

so wie Lothar das beschrieben hat, ist es am besten, meiner Meinung nach zumindest mittlerweile auch. 8) Ich habe jetzt mal 10 Tables so behandelt. Hierfür brauche ich pro Table ca. einen Tag, weil da einiges an überflüssigem, unlogischem drin ist (auf der Datenseite) und die Konvertierung inklusive Fehlerbereinigung (Delphi-mäßig) halt dauert.

Um das etwas zu beschleunigen schreib ich das hier rein, vielleicht hat ja noch einer eine Idee. Da gibts nämlich noch 20 Tables. :| Was mich aufhält, ist vor allem das zerstückeln der Zeile mit den alten Daten, bzw. das Einfügen in die DB. Das muß alles von Hand abgezählt werden. Dann kommt eine Fehlermeldung und wieder die nächste. Um das zu vereinfachen habe ich die Felder der Ursprungsdaten möglichst gleich behandelt : Prozedur für jeden Typ mit festgelegter Feldlänge in der Textdatei, aber dann wird es alles zu lang.

Wie sollte man da vielleicht besser vorgehen ? Also mir fällt nicht mehr viel dazu ein. Glaube fast, in der Richtung geht nix mehr, aber wer weiß ? :shock:

Gruß
Hansa