【问题标题】:For xml path returns null instead of nothing对于 xml 路径返回 null 而不是什么都没有
【发布时间】:2023-03-16 22:39:01
【问题描述】:

我认为下面的查询假设什么都不返回,但是,它返回一个记录,其中包含一个包含null 的列:

select *
from ( select 1 as "data"
       where 0 = 1
       for xml path('row') ) as fxpr(xmlcol)

如果您只运行子查询 - 不返回任何内容,但是当此子查询有外部查询时,对其执行 select,则返回 null

为什么会这样?

【问题讨论】:

  • 是的,我最初误读了您的帖子。道歉。
  • @Larnu,没问题,伙计)

标签: sql-server xml tsql for-xml-path select-for-xml


【解决方案1】:

SQL Server 将尝试预测类型。看看这个

SELECT tbl.[IsThereAType?] + '_test'
      ,tbl.ThisIsINT       + 100
FROM
(
    SELECT NULL AS [IsThereAType?]
          ,3 AS ThisIsINT
    UNION ALL 
    SELECT 'abc'
          ,NULL
    --UNION ALL 
    --SELECT 1  
    --    ,NULL
) AS tbl;

第一列将被预测为字符串类型,而第二列被视为INT。这就是顶部的+ 运算符起作用的原因。尝试将数字添加到第一个或字符串添加到第二个。这将失败。

尝试取消注释最后一个块,它也会失败。

预测是在很早的阶段完成的。看看这个,我确实在其中包含了第三个UNION ALL(无效查询,破坏了类型):

EXEC sp_describe_first_result_set 
N'SELECT *
FROM
(
    SELECT NULL AS [IsThereAType?]
          ,3 AS ThisIsINT
    UNION ALL 
    SELECT ''abc''
          ,NULL
    UNION ALL 
    SELECT 1
          ,NULL

) AS tbl';

结果返回“IsThereAType?”作为INT! (我很确定这是相当随机的,并且在您的系统上可能会有所不同。)
顺便说一句:如果没有最后一个块,类型是 VARCHAR(3)...

现在回答你的问题

XML 被视为NTEXT(尽管已弃用!)并且需要将,TYPE 预测为XML

EXEC sp_describe_first_result_set N'SELECT ''blah'' FOR XML PATH(''blub'')';
EXEC sp_describe_first_result_set N'SELECT ''blah'' FOR XML PATH(''blub''),TYPE';

包裹在子选择中的相同返回为NVARCHAR(MAX) resp。 XML

EXEC sp_describe_first_result_set N'SELECT * FROM(SELECT ''blah'' FOR XML PATH(''blub'')) AS x(y)';
EXEC sp_describe_first_result_set N'SELECT * FROM(SELECT ''blah'' FOR XML PATH(''blub''),TYPE) AS x(y)';

嗯,这实际上有点奇怪...... XML 是一个标量值,取为NTEXTNVARCHAR(MAX)XML(取决于您调用它的方式)。但不允许在子选择中放置 naked 标量:

SELECT * FROM('blah') AS x(y) --fails

虽然没关系

SELECT * FROM(SELECT 'blah') AS x(y)    

结论:

在您的特殊情况下,查询解析器似乎略有不一致:

虽然子选择不能只包含一个标量值,但SELECT ... FOR XML(实际上返回一个标量)不会被拒绝。引擎似乎将此解释为 SELECT 返回一个标量值。这完全没问题。

这对于嵌套子选择作为列(相关子查询)来嵌套 XML 很有用:

SELECT TOP 5 t.TABLE_NAME
            ,(
              SELECT COLUMN_NAME,DATA_TYPE 
              FROM INFORMATION_SCHEMA.COLUMNS AS c
              WHERE c.TABLE_SCHEMA=t.TABLE_SCHEMA
                AND c.TABLE_NAME=t.TABLE_NAME
              FOR XML PATH('Column'),ROOT('Columns'),TYPE
             ) AS AllTablesColumns
FROM INFORMATION_SCHEMA.TABLES AS t;

如果没有FOR XML 子句,这将失败(...多个值... / ...只有一列...

将通用SELECT 作为参数传递?

有些人会说这是不可能的,但你可以试试这个:

CREATE FUNCTION dbo.TestType(@x XML)
RETURNS TABLE
AS
RETURN
SELECT @x AS BringMeBack;
GO

--The SELECT must be wrapped in paranthesis!
SELECT *
FROM dbo.TestType((SELECT TOP 5 * FROM sys.objects FOR XML PATH('x'),ROOT('y')));
GO

DROP FUNCTION dbo.TestType;

【讨论】:

    【解决方案2】:

    XML 数据在 SQL Server 中被视为 NULL

    select *
    from ( select 1 as "data"
           where 0 = 1
           for xml path('row') ) as fxpr(xmlcol)
    

    子查询将首先执行,子查询的结果即 (Empty Rowset) 将被转换为 XML 因此,得到 NULL价值。

    【讨论】:

    • 即使没有type 选项,它是否会被转换为XML?当您运行 exec sp_describe_first_result_set N'select * from ( select 1 as "data" for xml path(''row'') ) as fxpr(xmlcol)' 时,它会说该列具有 nvarchar(max) 类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 2021-09-13
    • 1970-01-01
    相关资源
    最近更新 更多