2017-09-05 12 views
3
파이어

에위한 추가적인 텍스트와 문자열 열에서 정수 값을 추출하고 난 그것에 매우 편리한 변환이 있습니다내가 (3.X, 2.5되지 않음) 파이어 버드에 BDE 쿼리 (역설)를 변환하고있어

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 값 (주문 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를 찾거나 쓰거나 저장 프로 시저에서 해킹 문자열 조작을 수행해야합니다. –

+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로 옮길 때 한 번 더 수행하는 것이 좋습니다. 그리고 그 시점부터 새 데이터 행을 입력 할 때 응용 프로그램을 작성하면 BOTH 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

당신의 ORDER order2, order1 될 것이라고이 예에서 그

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; 

같은 뭔가

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

또한, 실제로 열에는 복합 데이터가 포함되어 있습니다 : 정수 인덱스와 선택적 텍스트 접미사. 그렇다면, 가지고있는 데이터는 정규화되지 않고 테이블을 더 잘 재구성해야합니다. 당신 변환기 응용 프로그램 체크를하고 두 개의 새로운 열에 "1 개 비스 '와 같은 값들을 분할 - 당신이 파이어 버드에 역설에서 데이터를 이동하는 것

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

.

그리고 쿼리는 것입니다 당신이를 사용할 수 있습니다 fb2.5 사용하는 경우

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

예제 및 조언이 많기 때문에 레거시 응용 프로그램이 아직 존재하므로 첫 번째 예제를 사용하겠습니다. 이 상태와 'my_int_column'beeing에 대한 조건이 이미 채워져 있는지 여부와 인덱스가 있으면 더 빨리 될 수 있습니다! 잘 했어 :) – Darkendorf

+0

@Darkendorf ur 레거시 응용 프로그램은 구식이며 매우 문제가있는 BDE로 작동합니다. 필자는 SQL로 이동하는 것이 어쨌든 어떤 최신의 데이터 액세스 라이브러리를 사용하여 응용 프로그램을 개조해야한다고 생각합니다. 그래서 어쨌든 당신이 그것을 약간 재 설계해야한다면 앱 전체에서이 특정 필드 액세스 방법을 수정하는 좋은 시간이 될 수도 있습니다. –

+0

나는이 앱의 소스 코드를 볼 권리가있는 사람이 아니다 ... 나는 올해 후반에 움직이기를 바란다.하지만 지금은 내 앱을 사이드 바이 사이드와 함께 준비 할 필요가있다. 낡은 것 ... 적어도 같은 결과가 있습니다. – Darkendorf

1

같은 : fb3.0에서

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 

당신이 더 편리한 방법이 같은

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