2012-01-03 112 views
0

我需要將xml發送到存儲過程。在XML會是什麼樣子從xml生成動態where子句

<NewDataSet> 
<param> 
<SearchField>EmployeeID</SearchField> 
<FilterCondition> >= </FilterCondition> 
<ConditionData>201</ConditionData> 
<MatchCase>0</MatchCase> 
</params> 
<param>  
<SearchField>DeptID</SearchField> 
<FilterCondition> = </FilterCondition> 
<ConditionData>AC01</ConditionData> 
<MatchCase>0</MatchCase> 
</params> 
<param>  
<SearchField>Dob</SearchField> 
<FilterCondition> <= </FilterCondition> 
<ConditionData>23-MAR-2010</ConditionData> 
<MatchCase>0</MatchCase> 
</params> 
</NewDataSet> 
  1. SearchField標籤保持在其搜索將發生
  2. FilterCondition中的標籤將持有我用它來搜索和比較像'%「< =」'運營商的搜索字段名稱< =」等
  3. 我們將搜索
  4. MatchCase
  5. ConditionData標籤將實際值表明它會區分大小寫或不

我可以加載xml並在遊標的while循環中迭代並生成where子句。我的問題是我如何生成基於字段數據類型的where子句。

如果字段是字符串,則我們總是比較喜歡用「」單引號 如果字段爲數字或位類型,那麼我們就可以,如果該字段爲日期時間的話,我喜歡比較喜歡 沒有單引號 比較convert(@dob,varchar,112) > '20100101'

所以我的問題是如何根據數據類型生成where子句。 我需要動態獲取字段數據類型,並據此構建where子句。 請分享最好的想法。謝謝


我改變我的xml位。我包括每個領域的表名。所以請告訴我,我需要在這個SQL中更改以顯示每個字段的數據類型。顯示我需要加入系統表的數據類型。所以請在ur sql中做必要的更改以便與sys表聯接以獲取&顯示每個字段的數據類型。

INSERT INTO @tbl_WhereClause (SearchField, Operator, ConditionData, MatchCase,TableName) 
SELECT A.B.value('(SearchField)[1]', 'VARCHAR(255)') SearchField, 
    A.B.value('(FilterCondition)[1]', 'VARCHAR(25)') Operator, 
    A.B.value('(ConditionData)[1]', 'VARCHAR(MAX)') ConditionData, 
    A.B.value('(MatchCase)[1]', 'BIT') MatchCase, 
    A.B.value('(Table)[1]', 'VARCHAR(MAX)') TableName 
FROM @WhereClause_XML.nodes('/NewDataSet/param') A(B) 

這裏是我的解決方案。

/* 
XML DATA SAMPLE 
<NewDataSet> 
<param> 
    <SearchField>EmpID</SearchField> 
    <FilterCondition> >= </FilterCondition> 
    <ConditionData>201</ConditionData> 
    <MatchCase>0</MatchCase> 
    <Table>Employee</Table> 
</param> 
<param> 
    <SearchField>DeptName</SearchField> 
    <FilterCondition> = </FilterCondition> 
    <ConditionData>AC01</ConditionData> 
    <MatchCase>1</MatchCase> 
    <Table>Department</Table> 
</param> 
<param> 
    <SearchField>Dob</SearchField> 
    <FilterCondition> >= </FilterCondition> 
    <ConditionData>20120104</ConditionData> 
    <MatchCase>0</MatchCase> 
    <Table>Employee</Table> 
</param> 
    </NewDataSet>' 
    */ 

    CREATE PROCEDURE GenericSearch 
    (
@WhereClause_XML XML, 
@LogicalOperator VARCHAR(3) 
) 
    AS 

BEGIN 

DECLARE @SearchField VARCHAR(255), 
@Operator VARCHAR(25), 
@ConditionData VARCHAR(MAX), 
@MatchCase BIT, 
@TableName VARCHAR(MAX), 
@Validity VARCHAR(100), 
@ColumnType VARCHAR(128), 
@ColumnPrecision INT, 
@ColumnScale INT, 
@ColumnNullable bit, 
@WhereClause VARCHAR(MAX) 

DECLARE @tbl_WhereClause AS TABLE 
(
SearchField VARCHAR(255), 
Operator VARCHAR(25), 
ConditionData VARCHAR(MAX), 
MatchCase BIT, 
TableName VARCHAR(MAX), 
Validity VARCHAR(100), 
ColumnType VARCHAR(128), 
ColumnPrecision INT, 
ColumnScale INT, 
ColumnNullable bit 
) 


INSERT INTO @tbl_WhereClause (SearchField, Operator, ConditionData, MatchCase,TableName, 
Validity, ColumnType, ColumnPrecision, ColumnScale, ColumnNullable) 

SELECT A.B.value('(SearchField)[1]', 'VARCHAR(255)') SearchField, 
A.B.value('(FilterCondition)[1]', 'VARCHAR(25)') Operator, 
A.B.value('(ConditionData)[1]', 'VARCHAR(MAX)') ConditionData, 
A.B.value('(MatchCase)[1]', 'BIT') MatchCase, 
A.B.value('(Table)[1]', 'VARCHAR(MAX)') TableName, 
CASE WHEN t.NAME+c.NAME IS NULL THEN 'invalid' ELSE 'valid' END , 
ty.NAME, 
c.PRECISION, 
c.Scale, 
c.Is_Nullable 
FROM @WhereClause_XML.nodes('/NewDataSet/param') A(B) 
LEFT JOIN sys.tables t ON t.name = A.B.value('(Table)[1]', 'VARCHAR(MAX)') 
LEFT JOIN sys.COLUMNS c ON T.OBJECT_ID = c.OBJECT_ID AND c.name =  A.B.value('(SearchField)[1]', 'VARCHAR(255)') 
LEFT JOIN sys.types ty ON c.system_type_id = ty.system_type_id 

--SELECT * FROM @tbl_WhereClause 

SET @WhereClause= 'WHERE 1=1' 
DECLARE SearchCursor CURSOR FOR 
SELECT * FROM @tbl_WhereClause 

OPEN SearchCursor 

FETCH NEXT FROM SearchCursor 
INTO @SearchField, @Operator,@ConditionData,@MatchCase,@TableName,@Validity,@ColumnType,@ColumnPrecision,@Colu mnScale,@ColumnNullable 

WHILE @@FETCH_STATUS = 0 
BEGIN 

IF CHARINDEX('INT', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('NUMERIC', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('BIT', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('DECIMAL', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('FLOAT', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('REAL', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('MONEY', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+space(1)[email protected] 
END 
ELSE IF CHARINDEX('DATE', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + 'CONVERT(varchar,'[email protected]+',112)' + space(1)[email protected]+'CONVERT(varchar,'''[email protected]+''',112)' 
END 
ELSE IF CHARINDEX('CHAR', UPPER(@ColumnType)) > 0 
BEGIN 
    SET @WhereClause = @WhereClause + space(1)+ @LogicalOperator + space(1) + @SearchField + space(1)[email protected]+''''[email protected]+'''' 
END 

FETCH NEXT FROM SearchCursor 
INTO @SearchField, @Operator,@ConditionData,@MatchCase,@TableName,@Validity,@ColumnType,@ColumnPrecision,@ColumnScale,@ColumnNullable 
    END 

    CLOSE SearchCursor 
    DEALLOCATE SearchCursor 

    SELECT @WhereClause 
    END 
+0

您確定要在SQL中執行此操作嗎?如果你在調用SQL的代碼中這樣做會更好嗎?該代碼的語言是什麼? – svick 2012-01-03 15:01:33

+0

嗨托馬斯道歉,我的答覆很慢。你的解決方案對我來說很好。我認爲這只是一個報告構造函數,因此構建查詢的性能並不是一個優先事項。我不會喋喋不休地介紹遊標的使用等。我能發現的唯一可能會導致你問題的是你傳入你的字符串的@ConditionData var,如果它包含一個單引號的字符串,你的結果查詢將會出現語法錯誤 - 您可能想要將其轉義。 – HeavenCore 2012-01-04 22:10:27

+0

謝謝指出好東西。所以我會用@ConditionData中的雙引號替換單引號,如 REPLACE(@ConditionData,'''','''''')。任何其他建議 – Thomas 2012-01-05 07:07:43

回答

1

2小東西,1 < &>等都是以XML標記十分非法的,如果你要可靠地分析它,無論是生成的XML將需要這些編碼爲選擇恰當的實體引用:

&lt; < less than 
&gt; > greater than 
&amp; & ampersand 
&apos; ' apostrophe 
&quot; " quotation mark 

而且,您的交易節點和節點開有一個錯字,例如<PARAM>由<PARAMS>關閉(注意是「S」) - 假設這是一個錯字。

也就是說,最難的部分是將XML解析爲可用於構建動態SQL的有用數據。讓我 -

DECLARE @tbl_WhereClause AS TABLE (
    SearchField VARCHAR(255), 
    Operator VARCHAR(25), 
    ConditionData VARCHAR(MAX), 
    MatchCase BIT 
) 

DECLARE @WhereClause_XML XML 
SET @WhereClause_XML = ' 
<NewDataSet> 
<param> 
<SearchField>EmployeeID</SearchField> 
<FilterCondition> &gt;= </FilterCondition> 
<ConditionData>201</ConditionData> 
<MatchCase>0</MatchCase> 
</param> 
<param>  
<SearchField>DeptID</SearchField> 
<FilterCondition> = </FilterCondition> 
<ConditionData>AC01</ConditionData> 
<MatchCase>0</MatchCase> 
</param> 
<param>  
<SearchField>Dob</SearchField> 
<FilterCondition> &lt;= </FilterCondition> 
<ConditionData>23-MAR-2010</ConditionData> 
<MatchCase>0</MatchCase> 
</param> 
</NewDataSet>' 

INSERT INTO @tbl_WhereClause (SearchField, Operator, ConditionData, MatchCase) 
SELECT A.B.value('(SearchField)[1]', 'VARCHAR(255)') SearchField, 
     A.B.value('(FilterCondition)[1]', 'VARCHAR(25)') Operator, 
     A.B.value('(ConditionData)[1]', 'VARCHAR(MAX)') ConditionData, 
     A.B.value('(MatchCase)[1]', 'BIT') ConditionData 
FROM @WhereClause_XML.nodes('/NewDataSet/param') A(B) 

SELECT * FROM @tbl_WhereClause 

一旦你的分析數據,它只是一個簡單的情況下(如果不是乏味)通過表迭代和構建地方CLASE字符串:您可以通過解析XML到表中做到這一點知道你是否需要該部分的幫助。

+0

好主意我會嘗試生成where子句,但'(SearchField)[1]。爲什麼它總是(SearchField)[1]和(FilterCondition)[1] – Thomas 2012-01-04 07:56:55

+0

我編輯我的帖子,請看看和答案,如果可能的話。謝謝 – Thomas 2012-01-04 09:53:56

+0

非常感謝你的支持,幫助初次啓動。新年快樂。這裏是我最新的腳本,你可以從中瞭解我如何在sql server中開發一個通用搜索SP。我追加在我的帖子的底部。如果可以開發出更好的方法,請看一下並評論一下。謝謝 – Thomas 2012-01-04 13:59:54