2017-09-05 3 views
3

Ich bin eine BDE-Abfrage (Paradox) zu einer Firebird Konvertierung (2.5, nicht 3.x), und ich habe eine sehr günstige Umwandlung in ihm:Auszug Integer-Wert von String-Spalte mit additonal Text in Firebird

select TRIM('  1') as order1, CAST('  1' AS INTEGER) AS order2 --> 1 
select TRIM(' 1 bis') as order1, CAST(' 1 bis' AS INTEGER) AS order2 --> 1 

dann durch den geworfenen Wert der Bestellung wird der trimed Wert (ORDER order2, Order1) bietet mir das Ergebnis ich brauche:

1 
1 bis 
2 ter 
100 
101 bis 

Aber in Firebird eine falsches integer CASTING wird eine Ausnahme ausgelöst, und ich fand keinen Weg um das gleiche Ergebnis zu liefern. Ich glaube, ich kann sagen, ob eine Zahl mit so etwas wie unten vorhanden ist, aber ich kann nicht einen Weg zu extrahieren ...

TRIM(' 1 bis') similar to '[ [:ALPHA:]]*[[:DIGIT:]]+[ [:ALPHA:]]*' 

[EDIT]

Ich hatte zu handhaben finden Fälle, in denen Text vor der Zahl waren, so Arioch'The Trigger @ ich dieses große Lauf bekam:

SET TERM^; 
CREATE TRIGGER SET_MYTABLE_INTVALUE FOR MYTABLE ACTIVE 
BEFORE UPDATE OR INSERT POSITION 0 
AS 
DECLARE I INTEGER; 
DECLARE S VARCHAR(13); 
DECLARE C VARCHAR(1); 
DECLARE R VARCHAR(13); 
BEGIN 
    IF (NEW.INTVALUE is not null) THEN EXIT; 
    S = TRIM(NEW.VALUE); 
    R = NULL; 
    I = 1; 
    WHILE (I <= CHAR_LENGTH(S)) DO 
    BEGIN 
    C = SUBSTRING(S FROM I FOR 1); 
    IF ((C >= '0') AND (C <= '9')) THEN LEAVE; 
    I = I + 1; 
    END 
    WHILE (I <= CHAR_LENGTH(S)) DO 
    BEGIN 
    C = SUBSTRING(S FROM I FOR 1); 
    IF (C < '0') THEN LEAVE; 
    IF (C > '9') THEN LEAVE; 
    IF (C IS NULL) THEN LEAVE; 
    IF (R IS NULL) THEN R=C; ELSE R = R || C; 
    I = I + 1; 
    END 
    NEW.INTVALUE = CAST(R AS INTEGER); 
END^ 
SET TERM ;^
+0

Es gibt nichts in Firebird 2.5 selbst, das dies tun würde. Sie müssen eine UDF finden (oder schreiben), die dies tut, oder eine Hacky-String-Manipulation in einer gespeicherten Prozedur durchführen. –

+2

Beachten Sie, dass diese Frage für Firebird 2.5 ist. In 3.0 könnte man [SubString mit regulären Ausdrücken] (https://firebirdsql.org/file/documentation/release_notes/html/en/3_0/bk01ch09s05.html#rnfb30-dml-substring) verwenden. – NineBerry

+0

Danke @NineBerry für die Bearbeitung des Titels, natürlich hatte BDE nichts zum Ziel meiner Anfrage zu tun ... und natürlich ja, mir sind Firebird 3 Verbesserungen bekannt ... Ich denke ein neues Feld mit dem Integer-Wert wäre die beste Lösung, um Berechnungen jedes Mal zu vermeiden, wenn es benötigt wird ... – Darkendorf

Antwort

2

Konvertieren einer solchen Tabelle, haben Sie für das halten der extrahierten integer-Daten eine spezielle indizierte integer-Spalte hinzuzufügen.

Hinweis, diese Abfrage bei der Verwendung "sehr bequeme Konvertierung" ist eigentlich ziemlich schlecht: Sie sollten indizierte Spalten verwenden, um große Datenmengen zu sortieren (bestellen), sonst gehen Sie in die langsame Ausführung und verschwenden viel Speicher/Festplatte für temporäre Sortiertische.

Sie müssen also eine zusätzliche ganzzahlige Indexspalte hinzufügen und in der Abfrage verwenden.

Nächste Frage ist, wie man diese Spalte auffüllt.

Besser wäre es einmal zu tun, wenn Sie Ihre gesamte Datenbank und Anwendung von BDE auf Firebird verschieben. Und ab diesem Punkt füllen Sie Ihre Anwendung bei der Eingabe neuer Datenzeilen BEIDE varchar und integer Spalten richtig.

Einmalige Konvertierung kann dann von Ihrem Konverter-Anwendung durchgeführt werden. Oder Sie können wählbar Stored Procedure verwenden, die die Tabelle mit dieser und addierten Spalte wiederholen würde. Oder Sie können Execute Block machen, die durch die Tabelle iterieren und ihre Zeilen aktualisieren würde, um den besagten ganzzahligen Wert zu berechnen.

How to SELECT a PROCEDURE in Firebird 2.5

Wenn Sie Legacy-Anwendungen halten müssten, dass nur Textspalte einfügen, aber nicht Spalte integer, dann denke ich, Sie würden BEFORE UPDATE OR INSERT löst in Firebird verwenden, das würde die Textspalte Wert Brief parsen durch Buchstabe und extrahiere Ganzzahl daraus. Und dann stellen Sie sicher, dass Ihre Anwendung diese Integer-Spalte niemals direkt ändert.

Sehen Sie ein Trigger Beispiel bei Trigger on Update Firebird

PSQL Sprache Dokumentation: https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql.html

Ob Prozedur oder Trigger schreiben würde die angebaute ganze Zahl indizierten Spalt zu füllen, würden Sie einfach Schleife über Zeichen machen müssen, Kopieren String von der ersten Ziffer bis zur ersten Ziffer.

https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-functions-scalarfuncs.html#fblangref25-functions-string

https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql-coding.html#fblangref25-psql-declare-variable

etwas wie das

CREATE TRIGGER my_trigger FOR my_table 
BEFORE UPDATE OR INSERT 
AS 
DECLARE I integer; 
DECLARE S VARCHAR(100); 
DECLARE C VARCHAR(100); 
DECLARE R VARCHAR(100); 
BEGIN 
    S = TRIM(NEW.MY_TXT_COLUMN); 
    R = NULL; 
    I = 1; 
    WHILE (i <= CHAR_LENGTH(S)) DO 
    BEGIN 
    C = SUBSTRING(s FROM i FOR 1); 
    IF (C < '0') THEN LEAVE; 
    IF (C > '9') THEN LEAVE; 
    IF (C IS NULL) THEN LEAVE; 

    IF (R IS NULL) THEN R=C; ELSE R = R || C; 
    I = I + 1; 
    END 

    NEW.MY_INT_COLUMN = CAST(R AS INTEGER); 
END; 

In diesem Beispiel Ihre ORDER order2, order1

SELECT ..... FROM my_table ORDER BY MY_INT_COLUMN, MY_TXT_COLUMN 

werden würde

Darüber hinaus scheint Ihre Spalte tatsächlich zusammengesetzte Daten zu enthalten: ein ganzzahliger Index und ein optionaler Textpostfix. Wenn dies der Fall ist, werden die Daten, die Sie haben, nicht normalisiert und die Tabelle wird besser umstrukturiert.

CREATE TABLE my_table (
    ORDER_Int INTEGER NOT NULL, 
    ORDER_PostFix VARCHAR(24) CHECK(ORDER_PostFix = TRIM(ORDER_PostFix)), 

    ...... 

    ORDER_TXT COMPUTED BY (ORDER_INT || COALESCE(' ' || ORDER_PostFix, '')), 
    PRIMARY KEY (ORDER_Int, ORDER_PostFix) 
); 

Wenn Sie Ihre Daten von Paradox zu Firebird bewegen würde - Ihre Konverter Anwendung Prüfung machen und teilen diese Werte wie „1 bis“ in zwei neue Spalten.

Und Ihre Frage wäre dann wie

SELECT ORDER_TXT, ... FROM my_table ORDER BY ORDER_Int, ORDER_PostFix 
+1

voller Beispiele und Ratschläge, ich denke, ich werde mit Ihrem ersten Beispiel gehen, da die Legacy-Anwendung noch existiert. Damit und einer Bedingung auf 'my_int_column' bereits gefüllt oder nicht, und ein Index auf es, könnte es noch schneller werden! gut gemacht :) – Darkendorf

+0

@Darkendorf ur Legacy-Anwendung funktioniert mit veraltet und sehr problematisch heute BDE. Ich denke, um es in SQL zu verschieben, müssten Sie die App sowieso umgestalten, zumindest mit der modernen Datenzugriffsbibliothek. Es ist also vielleicht an der Zeit, diese spezifische Feldzugriffsmethode über die gesamte App hinweg zu überarbeiten, wenn Sie sie sowieso ein wenig neu gestalten müssten. –

+0

Ich bin nicht derjenige, der auch nur das Recht hat, sich diesen App-Quellcode anzuschauen ... Ich hoffe, dass die Dinge später in diesem Jahr weitergehen, aber jetzt muss ich meine App bereit machen, Seite an Seite zu arbeiten der alte ... mit mindestens dem gleichen Ergebnis. – Darkendorf

1

wenn Sie mit fb2.5 Sie Folgendes verwenden:

execute block (txt varchar(100) = :txt) 
returns (res integer) 
as 
declare i integer; 
begin 
    i=1; 
    while (i<=char_length(:txt)) do begin 
    if (substring(:txt from i for 1) not similar to '[[:DIGIT:]]') 
    then txt =replace(:txt,substring(:txt from i for 1),''); 
    else i=i+1; 
end 
res = :txt; 
suspend; 

end 

in fb3.0 Sie tun müssen, bequemer Weg, das gleiche

select 
cast(substring(:txt||'#' similar '%#"[[:DIGIT:]]+#"%' escape '#') as integer) 
from rdb$database