2017-09-05 2 views
3

Je convertir une requête BDE (Paradox) à un Oiseau de feu (2.5, 3.x pas) et j'ai une conversion très pratique en elle:Extrait Entier Valeur de chaîne Colonne avec additonal Texte dans 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 

ensuite la commande par la valeur casted la valeur trimed (ORDER order2, ORDER1) me fournir le résultat que j'ai besoin:

1 
1 bis 
2 ter 
100 
101 bis 

Mais dans Firebird cASTING un entier incorrect déclenche une exception et je ne trouve aucun moyen autour de fournir le même résultat. Je pense que je peux dire si un numéro est présent avec quelque chose comme ci-dessous, mais je ne pouvais pas trouver un moyen de l'extraire ...

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

[EDIT]

je devais gérer les cas où le texte étaient avant le numéro, donc en utilisant @ Arioch'The déclencheur je suis arrivé ce grand: courir

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

Il n'y a rien dans Firebird 2.5 lui-même qui ferait cela. Vous devrez trouver (ou écrire) un UDF qui fait cela, ou faire une manipulation de hacky string dans une procédure stockée. –

+2

Notez que cette question concerne Firebird 2.5. Dans la version 3.0, on pourrait utiliser [SubString with Regular expressions] (https://firebirdsql.org/file/documentation/release_notes/html/fr/3_0/bk01ch09s05.html#rnfb30-dml-substring). – NineBerry

+0

Merci @NineBerry pour l'édition du titre, bien sûr BDE n'avait rien à faire dans l'objectif de ma demande ... et bien sûr oui, je suis au courant des améliorations de Firebird 3 ... Je pense qu'un nouveau champ avec la valeur entière serait la meilleure solution pour éviter le calcul chaque fois que c'est nécessaire ... – Darkendorf

Répondre

2

Converting une telle table, vous devez ajouter une colonne entière indexé spécial pour garder les données entières extraites. Notez que cette requête en utilisant "conversion très pratique" est en fait plutôt mauvaise: vous devez utiliser des colonnes indexées pour trier de grandes quantités de données, sinon vous allez ralentir l'exécution et perdre beaucoup de mémoire/disque pour les tables de tri temporaires.

Vous devez donc ajouter une colonne indexée supplémentaire et l'utiliser dans la requête.

La question suivante est de savoir comment remplir cette colonne. Il vaudrait mieux le faire une fois, quand vous déplacez toute votre base de données et application de BDE vers Firebird. Et à partir de ce point, faites votre demande lors de la saisie de nouvelles lignes de données remplir correctement les colonnes varchar et integer.

Une conversion de temps peut être effectuée par votre application de conversion, puis. Ou vous pouvez utiliser Stored Procedure sélectionnable qui répéterait le tableau avec une telle colonne et ajouté. Ou vous pouvez créer Execute Block qui parcourrait la table et mettrait à jour ses lignes en calculant la valeur de cet entier.

How to SELECT a PROCEDURE in Firebird 2.5

Si vous devez conserver les applications existantes, que seule insérer colonne de texte, mais pas la colonne entier, alors je pense que vous devez utiliser BEFORE UPDATE OR INSERT déclencheurs dans Firebird, ce serait analyser la lettre de valeur de la colonne de texte par lettre et en extrait un entier. Et assurez-vous que votre application ne modifie jamais directement cette colonne entière.

Voir un exemple de déclenchement à Trigger on Update Firebird

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

Que vous écririez procédure ou de trigger pour remplir ledit nombre entier ajouté colonne indexée, vous devez faire simple boucle sur les caractères, la copie chaîne du premier chiffre jusqu'au premier non-chiffre.

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

Quelque chose comme ça

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; 

Dans cet exemple, votre ORDER order2, order1 deviendrait

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

De plus, il semble que votre colonne contienne réellement une donnée composée: un index entier et un suffixe textuel optionnel. Si c'est le cas, les données que vous avez ne sont pas normalisées et la table doit être restructurée.

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) 
); 

Lorsque vous déplacez vos données de Paradox à Firebird - libeller votre chèque d'application de convertisseur et de diviser ces valeurs comme « 1 bis » en deux nouvelles colonnes.

Et votre requête serait alors comme

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

plein d'exemples et de conseils, je pense que je vais aller avec votre premier exemple depuis l'application existante existe toujours. avec ceci et une condition sur 'my_int_column' étant déjà remplie ou pas, et un index dessus, ça pourrait devenir encore plus rapide! bien fait :) – Darkendorf

+0

@Darkendorf votre application legacy fonctionne avec BDE aujourd'hui obsolète et très problématique. Je pense que pour passer à SQL vous auriez à réorganiser l'application de toute façon, au moins en utilisant une bibliothèque d'accès aux données moderne. Il peut donc être temps de revoir cette méthode d'accès sur le terrain dans toute l'application, si vous deviez de toute façon la redessiner. –

+0

Je ne suis pas celui qui a même le droit de regarder ce code source de l'application ... J'espère que les choses avanceront plus tard cette année, mais pour l'instant je dois rendre mon application prête à travailler côte à côte avec l'ancien ... avec au moins le même résultat. – Darkendorf

1

si vous utilisez fb2.5 vous pouvez utiliser les éléments suivants:

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 

à fb3.0 vous avez beaucoup plus pratique de le faire le même

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