如何在SQL Server中将XML用作搜索条件

时间:2016-05-19 09:16:41

标签: sql sql-server xml tsql

我在SQL Server中通过XML传递搜索条件:

DECLARE @XML AS XML, @hDoc AS INT, @SQL NVARCHAR (MAX)

SET @XML = '<?xml version="1.0" encoding="UTF-8"?>
<search>
  <CustomerID></CustomerID>
  <CustomerName>Raj</CustomerName>
  <CustomerAddress></CustomerAddress>
</search>'

EXEC sp_xml_preparedocument @hDoc OUTPUT, @XML

DECLARE @SEARCH_CRITERIA TABLE (CustomerID varchar(50) NULL, 
                                CustomerName varchar(50) NULL, 
                                CustomerAddress varchar(50) NULL)

INSERT INTO @SEARCH_CRITERIA
    SELECT CustomerID, CustomerName, CustomerAddress
    FROM OPENXML(@hDoc, 'search')
    WITH 
        (CustomerID [varchar](50) 'CustomerID',
         CustomerName [varchar](100) 'CustomerName',
         CustomerAddress [varchar](100) 'CustomerAddress')

SELECT * 
FROM @SEARCH_CRITERIA

客户表:

CREATE TABLE [dbo].[Customer]
(
    [cID] [int] NOT NULL,
    [cName] [varchar](255) NULL,
    [cdob] [date] NULL,
    [cgender] [varchar](5) NULL,

    CONSTRAINT [PK_Customer] 
        PRIMARY KEY CLUSTERED ([cID] ASC)
           WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                 IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, 
                 ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

数据:

INSERT INTO Customer(cID, cName, cdob, cgender)
VALUES (1, 'Bala', '1986-02-14', 'M'); 

INSERT INTO Customer(cID, cName, cdob, cgender)
VALUES (2, 'Raj', '1982-05-24', 'M'); 

INSERT INTO Customer(cID, cName, cdob, cgender)
VALUES (3, 'Keerthi', '1990-06-06', 'F');

AddressInfo表:

CREATE TABLE [dbo].[AddressInfo]
(
    [aID] [int] NOT NULL,
    [cID] [int] NOT NULL,
    [aAddress] [nvarchar](255) NULL,

    CONSTRAINT [PK_Address] 
        PRIMARY KEY CLUSTERED ([aID] ASC)
           WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
                 IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,  
                 ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

数据:

INSERT INTO AddressInfo(aID, cID, aAddress)
VALUES (1, 1, 'Bangalore, India');

INSERT INTO AddressInfo(aID, cID, aAddress)
VALUES (2, 2, 'Delhi, India');

INSERT INTO AddressInfo(aID, cID, aAddress)
VALUES (3, 3, 'Kochi, India');

请帮助我如何执行搜索过程。

我的预期输出:

让我们考虑上面提到的XML,CustomerName元素的值为 Raj

输出应为

    cID          cName          cdob          cgender          cAddress
___________________________________________________________________________
     2           Raj           1982-05-24      M              Delhi, India

1 个答案:

答案 0 :(得分:1)

根本不需要sp_xml_preparedocument。您可以使用@nodes之类的:

DECLARE @XML XML = '<?xml version="1.0" encoding="UTF-8"?>
<search>
  <CustomerID></CustomerID>
  <CustomerName>Raj</CustomerName>
  <CustomerAddress></CustomerAddress>
</search>';

WITH cte AS
(
   SELECT   CustomerID      = s.c.value('CustomerID[1]', 'NVARCHAR(100)') 
           ,CustomerName    = s.c.value('CustomerName[1]', 'NVARCHAR(100)')
           ,CustomerAddress = s.c.value('CustomerAddress[1]', 'NVARCHAR(100)')
   FROM @XML.nodes('/search') s(c)
)
SELECT DISTINCT c.*, i.aAddress
FROM Customer c
JOIN AddressInfo i
  ON c.cID = i.cID
JOIN cte
  ON cte.CustomerID = c.cID
  OR cte.CustomerName = c.cName
  OR cte.CustomerAddress = i.aAddress;

LiveDemo

请注意,如果您想要部分匹配,可以将加入条件更改为LIKEcte.CustomerName = c.cName完全匹配。

第二:如果您需要同时将所有搜索条件设为真,请将OR更改为AND

修改

部分匹配:

WITH cte AS
(
 SELECT   
  CustomerID      = NULLIF(s.c.value('CustomerID[1]', 'NVARCHAR(100)'),'')
  ,CustomerName    = NULLIF(s.c.value('CustomerName[1]', 'NVARCHAR(100)'),'')
  ,CustomerAddress = NULLIF(s.c.value('CustomerAddress[1]','NVARCHAR(100)'),'')
 FROM @XML.nodes('/search') s(c)
)
SELECT DISTINCT c.*, i.aAddress
FROM Customer c
JOIN AddressInfo i
  ON c.cID = i.cID
JOIN cte
  ON cte.CustomerID = c.cID
  OR c.cName  LIKE '%' + cte.CustomerName + '%'
  OR i.aAddress LIKE '%' + cte.CustomerAddress + '%';

LiveDemo2

请注意,LIKE %...%不是SARGable,而且效果可能不佳。