我有这样的表:
MYDATA
Company Reference FirstName Surname
1 A001 Test1Name Test1Surname
2 A001 Test2Name Test2Surname
3 A001 Test3Name Test3Surname
和保存此数据的xml变量@searchList
:
<list>
<item>
<company>1</company>
<reference>A001</reference>
</item>
<item>
<company>2</company>
<reference>A001</reference>
</item>
<item>
<company>3</company>
<reference>A001</reference>
</item>
</list>
通常在只有一个条件的地方我会做:
select * from dbo.MYDATA rec
where Reference in
(
select entity.value('(reference/text())[1]', 'varchar(32)')
from searchList.nodes('/list/item') as T(entity)
)
如果有两个条件(company = xml.company and reference = xml.reference
)则会变得更复杂。
一种方法是创建一个包含companyid和reference列的临时表,将xml中的所有内容插入到该临时表中,并在MYDATA表上进行连接。其他方式是类似的东西,但有子查询。
还有其他更优雅,最重要的表现方式来实现这一目标吗?
这就是我现在最好的表现结果:
DECLARE @tbl TABLE(Id INT, Company INT,Reference VARCHAR(10),FirstName VARCHAR(100),Surname VARCHAR(100));
INSERT INTO @tbl VALUES
(1, 1,'A001','Test1Name','Test1Surname')
,(2, 2,'A001','Test2Name','Test2Surname')
,(3, 3,'A001','Test3Name','Test3Surname');
DECLARE @xml XML=
N'<list>
<item>
<company>1</company>
<reference>A001</reference>
</item>
<item>
<company>2</company>
<reference>A001</reference>
</item>
<item>
<company>3</company>
<reference>A001</reference>
</item>
</list>';
WITH SEARCHLIST (company, reference) as
(
select li.value('(company/text())[1]', 'int') AS company
,li.value('(reference/text())[1]', 'nvarchar(max)') AS reference
from @xml.nodes('/list/item') AS A(li)
)
select rec.* from SEARCHLIST srl
left join @tbl rec on srl.reference = rec.Reference and srl.company = rec.Company
where rec.Id is not null;
答案 0 :(得分:1)
您可以使用CTE使用.nodes()
从XML中获取派生表。
这使您可以处理从XML中获取的值,就像它们是普通表一样:
DECLARE @tbl TABLE(Company INT,Reference VARCHAR(10),FirstName VARCHAR(100),Surname VARCHAR(100));
INSERT INTO @tbl VALUES
(1,'A001','Test1Name','Test1Surname')
,(2,'A001','Test2Name','Test2Surname')
,(3,'A001','Test3Name','Test3Surname');
DECLARE @xml XML=
N'<list>
<item>
<company>1</company>
<reference>A001</reference>
</item>
<item>
<company>2</company>
<reference>A001</reference>
</item>
<item>
<company>3</company>
<reference>A001</reference>
</item>
</list>';
WITH CTE AS
(
SELECT li.value(N'company[1]',N'int') AS company
,li.value(N'reference[1]',N'nvarchar(max)') AS reference
FROM @xml.nodes(N'/list/item') AS A(li)
)
SELECT *
FROM @tbl AS t
INNER JOIN CTE ON t.Reference=CTE.reference --use any column however you like it
说实话:你写其他方式是类似的东西,但有一个子查询。在这种情况下,CTE方法在技术上与子选择完全相同。
根据XML的大小,在大多数情况下,使用XML方法.exist()
的速度更快,您可以使用谓词来检查XPath
的存在性。
CTE appraoch必须读出整套,只是为了再次拆掉它。如果性能很重要,您也可以在.nodes()
中包含过滤谓词。
但最好的解决方案很大程度上取决于您的实际需求......
.exist()
尝试此操作(更改样本数据以携带不同的值)
DECLARE @tbl TABLE(Company INT,Reference VARCHAR(10),FirstName VARCHAR(100),Surname VARCHAR(100));
INSERT INTO @tbl VALUES
(1,'A001','Test1Name','Test1Surname')
,(2,'A002','Test2Name','Test2Surname')
,(3,'A004','Test3Name','Test3Surname'); <-- Will not be returned
DECLARE @xml XML=
N'<list>
<item>
<company>1</company>
<reference>A001</reference>
</item>
<item>
<company>2</company>
<reference>A002</reference>
</item>
<item>
<company>3</company>
<reference>A003</reference>
</item>
</list>';
select * from @tbl rec
where @xml.exist(N'/list/item/reference[text()=sql:column("Reference")]')=1