2

我需要從xml中構建我的sql查詢條件的一部分。從XML動態查詢構建循環條件?

我有一個XML等:

<ROOT> 
     <PARAMETROS> 
     <USU_LOGIN>yleon</USU_LOGIN> 
     <USU_NOMBREPRIMERO>Yerusha</USU_NOMBREPRIMERO> 
     <USU_APELLIDOPRIMERO>Leon</USU_APELLIDOPRIMERO> 
     <USU_EMAIL>[email protected]</USU_EMAIL> 
     <USU_FECHACREACION>20130510</USU_FECHACREACION> 
     <USU_CODICIONES1 TIPO="MC">AND USU_ID=4</USU_CODICIONES1> 
     <USU_CODICIONES2 TIPO="MC">AND USU_ID=5</USU_CODICIONES2> 
     <USU_CODICIONES3 TIPO="HG">AND USU_ID=9</USU_CODICIONES3> 
     ... 
     <USU_CODICIONESN TIPO="MC">AND USU_ID=50</USU_CODICIONESN> 
     </PARAMETROS> 
    </ROOT> 

所以我需要提取與屬性TIPO = 「MC」 的條件;我做這個代碼:

SELECT txt = T.Item.value('data(.)', 'varchar(255)') 
FROM @xml.nodes('/ROOT/PARAMETROS/*') AS T(Item) 
WHERE T.Item.value('data(@TIPO)', 'varchar(255)')='MC' 

現在,假設我的查詢是:

Select * from USUARIOS 
where 1=1 USU_CODICIONES1 USU_CODICIONES2 .. USU_CODICIONESn 

我需要更換「@@ USU_CODICIONESX」循環的XML,但不使用遊標,也許CTE。

預期的結果是:

Select * from USUARIOS 
where 1=1 AND USU_ID=4 AND USU_ID=5 .. AND USU_ID=50 

回答

2

您需要動態創建一個SQL語句,然後運行該命令

DECLARE @xml xml = 
    '<ROOT> 
     <PARAMETROS> 
     <USU_LOGIN>yleon</USU_LOGIN> 
     <USU_NOMBREPRIMERO>Yerusha</USU_NOMBREPRIMERO> 
     <USU_APELLIDOPRIMERO>Leon</USU_APELLIDOPRIMERO> 
     <USU_EMAIL>[email protected]</USU_EMAIL> 
     <USU_FECHACREACION>20130510</USU_FECHACREACION> 
     <USU_CODICIONES1 TIPO="MC">AND USU_ID=4</USU_CODICIONES1> 
     <USU_CODICIONES2 TIPO="MC">AND USU_ID=5</USU_CODICIONES2> 
     <USU_CODICIONES3 TIPO="HG">AND USU_ID=9</USU_CODICIONES3> 
     <USU_CODICIONESN TIPO="MC">AND USU_ID=50</USU_CODICIONESN> 
     </PARAMETROS> 
    </ROOT>' 

DECLARE @query nvarchar(max) = 
    'SELECT * FROM USUARIOS where 1=1 USU_CODICIONES1 USU_CODICIONES2 USU_CODICIONESn', 
     @dsql nvarchar(max) 

;WITH cte AS 
(  
    SELECT T.Item.value('fn:local-name(.)', 'varchar(255)') AS cond, 
     T.Item.value('data(.)', 'varchar(255)') AS NewCond, 
     ROW_NUMBER() OVER(ORDER BY 1/0) AS rn 
    FROM @xml.nodes('/ROOT/PARAMETROS/*') AS T(Item) 
    WHERE T.Item.value('data(@TIPO)', 'varchar(255)')='MC' 
), cte2 AS 
(
    SELECT rn, cond, newCond, REPLACE(@query, cond, NewCond) AS NewQuery 
    FROM cte 
    WHERE rn = 1 
    UNION ALL 
    SELECT c.rn, c.cond, c.newCond, REPLACE(c2.NewQuery, c.cond, c.NewCond) 
    FROM cte c JOIN cte2 c2 ON c.rn = c2.rn + 1 
) 
    SELECT TOP 1 @dsql = NewQuery 
    FROM cte2 
    ORDER BY rn DESC 

    --PRINT @dsql 
    EXEC sp_executesql @dsql 

或者使用字符串連接COALESCE/ISNULL功能

DECLARE @xml xml = 
    '<ROOT> 
     <PARAMETROS> 
     <USU_LOGIN>yleon</USU_LOGIN> 
     <USU_NOMBREPRIMERO>Yerusha</USU_NOMBREPRIMERO> 
     <USU_APELLIDOPRIMERO>Leon</USU_APELLIDOPRIMERO> 
     <USU_EMAIL>[email protected]</USU_EMAIL> 
     <USU_FECHACREACION>20130510</USU_FECHACREACION> 
     <USU_CODICIONES1 TIPO="MC">AND USU_ID=4</USU_CODICIONES1> 
     <USU_CODICIONES2 TIPO="MC">AND USU_ID=5</USU_CODICIONES2> 
     <USU_CODICIONES3 TIPO="HG">AND USU_ID=9</USU_CODICIONES3> 
     <USU_CODICIONESN TIPO="MC">AND USU_ID=50</USU_CODICIONESN> 
     </PARAMETROS> 
    </ROOT>' 

DECLARE @query nvarchar(max) = 
    'SELECT * FROM USUARIOS where 1=1 USU_CODICIONES1 USU_CODICIONES2 USU_CODICIONESn', 
     @dsql nvarchar(max) 

    SELECT @dsql = REPLACE(COALESCE(@dsql, @query), 
         T.Item.value('fn:local-name(.)', 'varchar(255)'), 
         T.Item.value('data(.)', 'varchar(255)'))   
    FROM @xml.nodes('/ROOT/PARAMETROS/*') AS T(Item) 
    WHERE T.Item.value('data(@TIPO)', 'varchar(255)')='MC' 
    --PRINT @dsql 
    EXEC sp_executesql @dsql 
+0

不錯的嘗試,但它必須在原始查詢中替換標記USU_CODICIONES1..USU _CODICIONESN爲xml元素USU_CODICIONES1..USU_CODICIONESN,它們可以按照不同的順序或原始查詢的一部分。 – Artemination

+1

答案已更新。請再試 –

+0

我認爲就像玩火一樣,查詢可能有很多其他的子選擇,當你反轉+ charindex +的最後一部分不會工作.. – Artemination