Dot-Net
是否有動態生成 sql 的標準方法?
我想問一下其他程序員如何生成動態 SQL 字元串以作為 SQLCommand 對象的 CommandText 執行。
我正在生成包含使用者生成的 WHERE 子句和 SELECT 欄位的參數化查詢。有時查詢很複雜,我需要對不同部分的建構方式進行大量控制。
目前,我正在使用許多循環和 switch 語句來生成必要的 SQL 程式碼片段並創建所需的 SQL 參數對象。這種方法很難遵循,它使維護成為一件真正的苦差事。
有沒有更清潔、更穩定的方法來做到這一點?
有什麼建議麼?
編輯:為我以前的文章添加細節:
- 由於要求,我無法真正模板化我的查詢。只是變化太大了。
- 我必須允許聚合函式,比如 Count()。這對 Group By/Having 條款有影響。它還會導致嵌套的 SELECT 語句。反過來,這會影響所使用的列名
- 一些聯繫人數據儲存在 XML 列中。使用者可以將這些數據連同其他關係列一起查詢。後果是 xmlcolumns 不能出現在 Group By 子句中$$ sql syntax $$.
- 我正在使用一種使用 Row_Number() SQL 函式的高效分頁技術。結果是我必須使用 Temp 表,然後在選擇我的子集之前獲取@@rowcount,以避免第二次查詢。
我將展示一些程式碼(恐怖!),以便你們了解我正在處理的內容。
sqlCmd.CommandText = "DECLARE @t Table(ContactId int, ROWRANK int" + declare + ")INSERT INTO @t(ContactId, ROWRANK" + insertFields + ")"//Insert as few cols a possible + "Select ContactID, ROW_NUMBER() OVER (ORDER BY " + sortExpression + " " + sortDirection + ") as ROWRANK" // generates a rowrank for each row + outerFields + " FROM ( SELECT c.id AS ContactID" + coreFields + from // sometimes different tables are required + where + ") T " // user input goes here. + groupBy+ " " + havingClause //can be empty + ";" + "select @@rowcount as rCount;" // return 2 recordsets, avoids second query + " SELECT " + fields + ",field1,field2" // join onto the other cols n the table +" FROM @t t INNER JOIN contacts c on t.ContactID = c.id" +" WHERE ROWRANK BETWEEN " + ((pageIndex * pageSize) + 1) + " AND " + ( (pageIndex + 1) * pageSize); // here I select the pages I want在此範例中,我正在查詢 XML 數據。對於純關係數據,查詢要簡單得多。每個部分變數都是 StringBuilders。Where 子句的建構方式如下:
// Add Parameter to SQL Command AddParamToSQLCmd(sqlCmd, "@p" + z.ToString(), SqlDbType.VarChar, 50, ParameterDirection.Input, qc.FieldValue); // Create SQL code Fragment where.AppendFormat(" {0} {1} {2} @p{3}", qc.BooleanOperator, qc.FieldName, qc.ComparisonOperator, z);
我需要在我最近的一個項目中這樣做。這是我用於生成 SQL 的方案:
- 查詢的每個組件都由一個對象表示(在我的例子中,它是一個映射到數據庫中表的 Linq-to-Sql 實體)。所以我有以下類:Query、SelectColumn、Join、WhereCondition、Sort、GroupBy。這些類中的每一個都包含與查詢的該組件相關的所有詳細資訊。
- 最後五個類都與一個 Query 對象相關。因此 Query 對象本身俱有每個類的集合。
- 每個類都有一個方法,可以為它所代表的查詢部分生成 SQL。因此,創建整體查詢最終會呼叫 Query.GenerateQuery() 依次列舉所有子集合併呼叫它們各自的 GenerateQuery() 方法
它仍然有點複雜,但最終您知道查詢的每個單獨部分的 SQL 生成源自何處(而且我不認為有任何大的 switch 語句)。並且不要忘記使用 StringBuilder。