2017-09-05 44 views
3

產生額外的文字,我轉換BDE查詢(矛盾)的火鳥(2.5,不3.x中),我有它的一個非常方便的轉換:從字符串列中提取整數值與火鳥

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 

然後由澆鑄值排序,則trimed值(ORDER order2,order1)提供給我的結果,我需要:

1 
1 bis 
2 ter 
100 
101 bis 

但在火鳥鑄造一個不正確的整數會拋出一個異常,我沒有找到任何辦法以提供相同的結果。我想,我可以告訴大家一個數字是不是存在的東西像下面,但我無法找到一個方法來提取它...

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

[編輯]

我不得不處理其中文本是在號碼前,所以使用@ Arioch'The觸發我得到了這個偉大的運行情況:

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

有沒有在火鳥2.5本身會這樣做。你需要找到(或寫入)這樣做的UDF,或者在存儲過程中做一些hacky字符串操作。 –

+2

請注意,這個問題是針對Firebird 2.5的。在3.0中,可以使用[SubString with Regular expressions](https://firebirdsql.org/file/documentation/release_notes/html/en/3_0/bk01ch09s05.html#rnfb30-dml-substring)。 – NineBerry

+0

感謝@NineBerry編輯標題,當然BDE在我的請求中沒有任何目標......當然是的,我知道Firebird 3的改進......我認爲一個新的字段與整數值將是避免每次需要計算的最佳解決方案... – Darkendorf

回答

2

轉換這樣的表,你必須添加一個特殊的索引整數列保持所提取的整數數據。

注意,這個查詢在使用「非常方便的轉換」時實際上是相當糟糕的:您應該使用索引列來排序(排序)大量數據,否則您將進入緩慢執行並浪費大量內存/磁盤用於臨時排序表。

所以你必須添加一個額外的整數索引列並在查詢中使用它。

下一個問題是如何填充該列。

當您將整個數據庫和應用程序從BDE移動到Firebird時,最好做一次。從這一點開始,當您輸入新數據行時,您的應用程序會正確填寫varcharinteger列。

然後,您的轉換器應用程序可以完成一次轉換。 或者您可以使用可選的Stored Procedure,這將重複與此列和添加列的表。或者你可以使Execute Block遍歷整個表並更新其計算所述整數值的行。

How to SELECT a PROCEDURE in Firebird 2.5

如果你需要保持遺留應用程序,只有插入文本列,但不是整數列,那麼我認爲你將不得不使用BEFORE UPDATE OR INSERT觸發火鳥,將分析文本列值信字母並從中提取整數。然後確保您的應用程序不會直接更改該整數列。

看到Trigger on Update Firebird

PSQL語言的文檔觸發例如:https://www.firebirdsql.org/file/documentation/reference_manuals/fblangref25-en/html/fblangref25-psql.html

無論你會寫程序或觸發器來填充所述添加的整數索引列,你將不得不作出簡單循環,字符,複製從第一個數字開始直到第一個非數字。

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

類似的東西

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; 

在這個例子中你ORDER order2, order1將成爲

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

此外,它看起來你的列實際上包含一個複合數據:一個整數索引和一個可選的文本後綴。如果是這樣,那麼你擁有的數據沒有被標準化,表格可以更好地重構。

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

當你從悖論移動數據到火鳥 - 讓你的轉換器使用檢查和分裂,如「1雙」這些值轉換成兩個新列。

然後你的查詢會是這樣,如果你使用的是fb2.5,你可以使用下面的

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

充滿了示例和建議,我想我會與你的第一個例子,因爲遺留的應用程序仍然存在。有了這個,'my_int_column'上的條件已經填滿或者沒有填滿,並且上面有一個索引,它可能會變得更快!做得好:) – Darkendorf

+0

@Darkendorf你的傳統應用程序與過時和非常有問題的今天BDE工作。我想將它移到SQL中,至少要使用一些現代化的數據訪問庫,不得不重新調整應用程序。因此,在整個應用程序中修改這種特定的字段訪問方法也許是個好時機,如果您無論如何都不得不重新設計它。 –

+0

我不是那個有權查看這個應用程序源代碼的人......我希望今年晚些時候能夠繼續前進,但現在我必須讓我的應用程序準備好並行工作舊的......至少有相同的結果。 – Darkendorf

1

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你有更方便的方式做同樣的

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