2012-11-08 35 views
2

我有火鳥2.5.2表:火鳥位置意外的行爲?

create table SearchTest (val varchar(20)) 

其中有兩行:

insert into SearchTest (val) values ('one') 
insert into SearchTest (val) values ('three') 

我想選擇其中列「VAL」包含任何「一」或所有行「HRE 」。使用LINQ我可以表達這種爲:

var a = from b in TestEntities.SEARCHTESTs 
     from c in new []{ "one", "hre" } 
     where b.VAL.Contains(c) 
     select b; 

這會產生這樣的查詢:

SELECT 
"C"."VAL" AS "VAL" 
FROM "SEARCHTEST" AS "C" 
CROSS JOIN (SELECT 
     _UTF8 X'4F4E45' AS "C1" 
     FROM (SELECT 1 AS X FROM RDB$DATABASE) AS "D" 
UNION ALL 
     SELECT 
     _UTF8 X'485245' AS "C1" 
     FROM (SELECT 1 AS X FROM RDB$DATABASE) AS "E") AS "F" 
WHERE ((POSITION("F"."C1", "C"."VAL")) > 0) 

爲了便於檢查的是,這個做同樣的事情:

SELECT 
    val, 
    substr, 
    POSITION(Substr, Val) as pos 
FROM 
    SearchTest 
CROSS JOIN 
(
    SELECT 'one' AS substr FROM RDB$DATABASE 
    UNION ALL 
    SELECT 'hre' AS substr FROM RDB$DATABASE 
) 

使用搜索詞'one'和'hre',結果如您所料:

val substr pos 
--- ------ --- 
one one 1 
three one 0 
one hre 0 
three hre 2 

但是,如果搜索詞的長度不匹配:

SELECT 
    val, 
    substr, 
    POSITION(Substr, Val) as pos 
FROM 
    SearchTest 
CROSS JOIN 
(
    SELECT 'one' AS substr FROM RDB$DATABASE 
    UNION ALL 
    SELECT 'hree' AS substr FROM RDB$DATABASE 
) 

匹配失敗:

val substr pos 
--- ------ --- 
one one 1 
three one 0 
one hree 0 
three hree 0 

如果我投的搜索詞(模具類型沒有匹配,如如圖所示):

SELECT 
    val, 
    substr, 
    POSITION(Substr, Val) as pos 
FROM 
    SearchTest 
CROSS JOIN 
(
    SELECT cast('one' as varchar(3)) AS substr FROM RDB$DATABASE 
    UNION ALL 
    SELECT cast('hree' as char(5)) AS substr FROM RDB$DATABASE 
) 

本場比賽再次工作:

val substr pos 
--- ------ --- 
one one 1 
three one 0 
one hree 0 
three hree 2 

這是爲什麼,有沒有辦法解決這個問題?

編輯:

吉日Cincura已經注意到這個錯誤是固定的下一個版本;字符串常量現在顯式轉換爲varchars。火鳥跟蹤問題:http://tracker.firebirdsql.org/browse/DNET-466

+0

爲什麼不使用SIMILAR TO運算符? –

+0

什麼是Firebird版本?乍一看,這看起來像一個錯誤,所以你可能還想在http://tracker.firebirdsql.org/browse/CORE –

回答

3

火鳥對待文字爲CHAR,所以當你這裏有不同的長度('one''hree')兩種文字,這將它們描述爲CHAR(4)

爲了說明這一點,在ISQL的輸出與SQLDA_DISPLAY ON爲類似的查詢是:

SQL> SET SQLDA_DISPLAY ON; 
SQL> SELECT 'one' as X FROM RDB$DATABASE 
CON> UNION ALL 
CON> SELECT 'hree' as x FROM RDB$DATABASE; 

INPUT SQLDA version: 1 sqln: 10 sqld: 0 

OUTPUT SQLDA version: 1 sqln: 20 sqld: 1 
01: sqltype: 452 TEXT     sqlscale: 0 sqlsubtype: 0 sqllen: 4 
    : name: (0) alias: (1)X 
    : table: (0) owner: (0) 

X 
====== 
one 
hree 

類型452 TEXT是火鳥類型CHAR列。 sqllen表示它的長度爲4.對於'one'這意味着它實際上是'one '(注意額外的空間)。所以當它被輸入到POSITION時,它不匹配,因爲你的原始值是'one'(如VARCHAR)。

我不知道這是否是在POSITION(的CHAR行爲是SQL標準的一個惱人的功能)的錯誤,或者如果火鳥的方式使用CHAR的文字將需要更改爲VARCHAR。但我確實很困惑,所以我建議將其報告爲http://tracker.firebirdsql.org/browse/CORE

上的一個錯誤現在,如果您正在編寫直接查詢,則解決方案與上例相同。既然你投的文字之一VARCHAR,工會會自動將所有值轉換爲VARCHAR

SQL> SELECT CAST('one' AS VARCHAR(3)) as X FROM RDB$DATABASE 
CON> UNION ALL 
CON> SELECT 'hree' as x FROM RDB$DATABASE; 

INPUT SQLDA version: 1 sqln: 10 sqld: 0 

OUTPUT SQLDA version: 1 sqln: 20 sqld: 1 
01: sqltype: 448 VARYING     sqlscale: 0 sqlsubtype: 21 sqllen: 4 
    : name: (0) alias: (1)X 
    : table: (0) owner: (0) 

X 
====== 
one 
hree 

類型448期變是火鳥類型VARCHAR。請注意,長度爲4而不是3,因爲Firebird會將其擴展到發現的最大尺寸(在UNION的第二部分中)。

由於您不是直接編寫SQL,所以我不確定這裏有什麼解決方案。您可以添加Firebird .NET提供程序的改進請求,以將這些值轉換爲VARCHAR以進行這些類型的轉換(在跟蹤器中的http://tracker.firebirdsql.org/browse/DNET

+1

上創建一個錯誤票。這解釋了它,謝謝!我在http://tracker.firebirdsql.org/browse/DNET-466 上創建了一個Firebird .NET Provider問題我受影響的代碼只處理大約50k行,所以我可以通過移動Contains()操作來解決此問題現在進入記憶。 – DaveK