使用For XML PATH 会影响Cross Apply 返回

时间:2023-11-19 13:01:38

昨天在写语句的时候,遇到了一个现象,其实就是使用 Cross Apply做一个拼接字符串的而已。比如

CREATE TABLE GoodsCatalog
(ID INT,
Name NVARCHAR(50)) CREATE TABLE Goods
(ID INT,
GoodsCatalogID INT,
Name NVARCHAR(50)) INSERT INTO GoodsCatalog
( ID, Name )
VALUES ( 1,'水果'),( 2,'体育用品') INSERT INTO Goods
( ID,GoodsCatalogID, Name )
VALUES (1,1,'苹果')
,(2, 1,'香蕉')
,(3, 2,'足球')
,(4, 2,'篮球') SELECT a.*,
STUFF(B.GoodName,1,1,'') AS GoodName
FROM GoodsCatalog a
CROSS APPLY (SELECT '-' + b.Name
FROM Goods b
WHERE b.GoodsCatalogID = a.ID FOR XML PATH('')) AS B(GoodName) /*
ID Name GoodName
1 水果 苹果-香蕉
2 体育用品 足球-篮球
*/

很平常是吧?但是如果在 GoodsCatalog  表里面添加多2条数据呢?就会变成这样了。明明说好的 Cross Apply会将不返回生成结果集的行喔!!为啥还会这样呢!?

INSERT INTO GoodsCatalog
( ID, Name )
VALUES ( 3,'海鲜'),( 4,'衣服') SELECT a.*,
STUFF(B.GoodName,1,1,'') AS GoodName
FROM GoodsCatalog a
CROSS APPLY (SELECT '-' + b.Name
FROM Goods b
WHERE b.GoodsCatalogID = a.ID FOR XML PATH('')) AS B(GoodName)

/*
ID Name GoodName
1 水果 苹果-香蕉
2 体育用品 足球-篮球
3 海鲜 NULL
4 衣服 NULL */

-------------------------------------------这是描述我是一个逗比的分割线--------------------------------------------------------------------------------------------------------------

重新看了下联机文档里面的Apply 的用法

使用 APPLY 运算符可以为实现查询操作的外部表表达式返回的每个行调用表值函数。表值函数作为右输入,外部表表达式作为左输入。通过对右输入求值来获得左输入每一行的计算结果,生成的行被组合起来作为最终输出。APPLY 运算符生成的列的列表是左输入中的列集,后跟右输入返回的列的列表。

就是说,无论是 Cross Apply 还是 Outer Apply 后面都是跟随一个表值函数,会与左边的输入表每一行进行交叉。所以是否返回应该看 ()里面的语句本身。

这里我又有疑问了,Goods 表里面没有 3,4 的结果啊,为什么还能显示。

这个就是函数的问题了。假如写2个表值函数对比一下就很清晰了

CREATE FUNCTION TestXML
(@GoodsCatalogID INT)
RETURNS @TABLE TABLE
(
GoodName varchar(200)
)
AS
begin
;WITH CTE(GoodName) AS
(SELECT '-' + Name FROM Goods
WHERE GoodsCatalogID = @GoodsCatalogID FOR XML PATH(''))
INSERT INTO @TABLE (GoodName)
SELECT GoodName
FROM CTE
RETURN
END CREATE FUNCTION TestTable
(@GoodsCatalogID INT)
RETURNS @TABLE TABLE
(
GoodName varchar(200)
)
AS
begin
INSERT INTO @TABLE (GoodName)
SELECT Name FROM Goods
WHERE GoodsCatalogID = @GoodsCatalogID
RETURN
END SELECT *
FROM dbo.TestXML(3) /*
GoodName
NULL
*/ SELECT *
FROM dbo.TestTable(3) /*
GoodName
*/

一个有返回,另外一个没有返回哦~~这个就知道为什么能交叉到值出来了吧。

--------------------------------------------------------------------------------------这是证明我不认真的打脸分割线------------------------------------------------------------------------------------------------------------------------

发现了这个问题,纯粹是因为对 Apply用法不清晰导致了……╮(╯_╰)╭~

为大家献丑了