2008-09-26 93 views
16

我上週寫了一些單元測試,用於生成一些SQL語句的一段代碼。正則表達式以匹配常見的SQL語法?

我試圖找出一個匹配SELECT,INSERT和UPDATE語法的正則表達式,這樣我就可以驗證我的方法是否生成有效的SQL,並且在搜索後和我放棄了各種正則表達式編輯器。

我設法獲得部分匹配,但由於引號中的某個部分可以包含任何字符,因此它可以快速擴展以匹配整個陳述。

任何幫助將不勝感激,我不是很好的正則表達式,但我想了解更多關於他們。

順便說一下,它是C#正則表達式,我後。

澄清

我不想需要對數據庫的訪問,因爲這是一個單元測試的一部分,我不wan't不得不維持一個數據庫來測試我的代碼。這可能比這個項目壽命更長。

回答

36

正則表達式只能匹配有限狀態自動機可以解析的語言,這是非常有限的,而SQL是一種語法。 可以證明你不能用正則表達式來驗證SQL。所以,你可以停止嘗試。

+0

同意。除了正則表達式,還需要其他一些方法。沒有辦法匹配select語句的合法語法:http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#SQLRF01702 – 2008-09-26 16:24:19

+0

同意。實際上,你需要一個SQL解析器。以下是一篇文章,介紹如何在通用SQL解析器的幫助下進行供應商特定的脫機SQL語法檢查:http://www.dpriver.com/blog/list-of-demos-illustrate-how-to-use-general -sql-parser/vendor-specific-offline-sql-syntax-check/ – 2012-01-08 12:15:31

0

您是否嘗試過懶惰選擇器。儘可能匹配,而不是儘可能匹配,這可能是你需要引用的。

0

我假設你做了類似「。*」的嘗試,而不是嘗試「[^」] *「,這會阻止你吃掉整條線,它仍然會給你帶有」 。

+0

不,我指定\的空格和連字符,它走到行的末尾 – 2008-09-26 14:45:44

1

關閉我的頭頂:您是否可以將生成的SQL傳遞給數據庫並在其上使用EXPLAIN並捕獲任何可能表明形成不良的SQL的異常?

+0

這對單元測試沒有用處,我可能不一定有權訪問數據庫,我知道它將始終運行 – 2008-09-26 14:47:33

+0

取決於服務器,例如,MySQL只允許在選擇的語句中解釋。 – pilsetnieks 2008-09-26 15:01:50

0

要驗證查詢,只需使用SET NOEXEC ON運行它們,這就是Entreprise Manager在解析查詢時不執行它的原因。

此外,如果您使用正則表達式來驗證sql查詢,幾乎可以肯定的是,您將錯過某些特定情況,或者由於其他原因而導致查詢無效,即使它在語法上是正確的。

0

我建議使用相同的模式創建一個數據庫,可能使用嵌入式sql引擎,並將sql傳遞給它。

0

我不認爲你甚至需要創建能夠驗證語句的模式,因爲系統不會嘗試解析object_name等,直到它成功解析語句爲止。

使用Oracle作爲一個例子,如果你這樣做,你一定會得到一個錯誤:

select * from non_existant_table; 

在這種情況下,「ORA-00942:表或視圖不存在」。

但是,如果你執行:

select * frm non_existant_table; 

然後你會得到一個語法錯誤, 「ORA-00923:FROM關鍵字未找到預期」。

它應該是可能的分類錯誤爲指示不正確的語法以及與表名和權限等錯誤語法解析錯誤..

添加到不同的RDBMS,甚至不同版本的問題,允許不同的語法我認爲你真的必須去數據庫引擎完成這項任務。

2

據我所知,這超出了正則表達式,並且越來越接近BnF和編譯器的黑暗藝術。

http://savage.net.au/SQL/

同樣的事情發生在誰想做正確的語法高亮人。你開始把東西塞進正則表達式,然後你最終編寫一個編譯器......

14

SQL是一個type-2 grammar,它太強大了,不能用正則表達式來描述。這與您決定生成C#代碼然後在不調用編譯器的情況下驗證它是一樣的。數據庫引擎通常太複雜,不容易被扼殺。

也就是說,你可以試試ANTLR's SQL grammars

0

ANTLR grammars來解析SQL。使用in memory database或者非常輕量級的數據庫如sqlite確實是一個更好的主意。從分析的角度來看,測試SQL是否有效似乎很浪費,並且檢查表和列的名稱以及查詢的具體情況會更有用。

1

我有同樣的問題 - 一種方法可以用於所有更標準的sql語句,將啓動內存中的Sqlite數據庫並對其發出查詢,如果返回「表不存在「錯誤,那麼你的查詢正確解析。

-1
public bool IsValid(string sql) 
{ 
string pattern = @"SELECT\s.*FROM\s.*WHERE\s.*"; 
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase); 
return rgx.IsMatch(sql); 
} 
0

最好的方法是驗證用於創建查詢的參數,而不是查詢本身。接收變量的函數可以檢查字符串的長度,有效的數字,有效的電子郵件或其他。您可以使用正則表達式來執行此驗證。