交叉应用使用的子查询不返回结果

Posted

技术标签:

【中文标题】交叉应用使用的子查询不返回结果【英文标题】:Cross Apply used Sub Query not Return Result 【发布时间】:2020-12-11 07:25:29 【问题描述】:

我想从deviceinfo 列中提取版本数据。为此,我使用 交叉应用

Order
----------------------------------
OrdeId       DeviceInfo                
----------------------------------    
10      PageSize|BGColor|3000|V1.0
11      PageSize|BGColor|3000|V2.0
12      PageSize|BGColor|3000|V3.0
----------------------------------

我使用了以下查询

Select * From 
(
    Select OrderId, DeviceInfo, Value, ROW_NUMBER() Over(Partition By DeviceInfo Order By OrderId Asc) As Rn
    FROM Order As Ord
    Cross Apply STRING_SPLIT(DeviceInfo, '|') As Di
    Where IsNull(Ord.DeviceInfo,'') != '' And OrderId='10'
)A Where A.Rn=4 And A.OrderId='10'

我得到了结果。

OrderId       DeviceInfo              Value  Rn
------------------------------------------------
10      PageSize|BGColor|3000|V1.0     V1.0  4

如果我在子查询中使用没有 orderid 过滤器的查询,我会得到 空结果

Select * From 
(
    Select OrderId, DeviceInfo, Value, ROW_NUMBER() Over(Partition By DeviceInfo Order By OrderId Asc) As Rn
    FROM Order As Ord
    Cross Apply STRING_SPLIT(DeviceInfo, '|') As Di
    Where IsNull(Ord.DeviceInfo,'') != ''
)A Where A.Rn=4 And A.OrderId='10'

请帮我解决这个问题

【问题讨论】:

你想要的结果是什么?使用 ROW_NUMBER,您只会得到一个结果(每个 DeviceInfo),即 OrderId 最低的结果。如果不过滤子查询,会得到 OrderId 的 我运行了您的两个示例查询,它们返回完全相同的结果集。您能否尝试重新解释您看到的问题并提供任何错误。 请不要在 WHERE 部分的列上使用函数。这可能对性能不利。更好地使用Ord.DeviceInfo IS NOT NULL OR Ord.DeviceInfo != '' @gofr1 在这种情况下,他们希望忽略 NULL 和空白。所以应该是AND。然而,他们在技术上只需要WHERE Ord.DeviceInfo <> '',空值会被自动过滤掉 【参考方案1】:

对意外结果的可能解释是以下问题的组合:

ROW_NUMBER() 函数调用中错误使用PARTITION BYORDER BY 子句。 ROW_NUMBER() Over (Partition By DeviceInfo Order By OrderId Asc) 以随机和意外的顺序编号行。 使用STRING_SPLIT() 按位置提取子字符串是一个棘手的方法。正如文档中的mentioned 一样,输出行可能是任何顺序,并且不保证该顺序与输入字符串中子字符串的顺序相匹配

在您的情况下(如果您想按位置提取子字符串),您可以尝试使用基于 JSON 的方法来解析 DeviceInfo 列。您需要将数据转换为有效的 JSON 数组(PageSize|BGColor|3000|V1.0 转换为 ["PageSize","BGColor","3000","V1.0"])并使用 OPENJSON() 解析该数组。 OPENJSON() 调用的结果是一个包含 keyvaluetype 列的表,key 列保存指定数组中元素的从 0 开始的索引。

表:

CREATE TABLE [Order] (
   OrderId int,
   DeviceInfo varchar(1000)               
)
INSERT INTO [Order] (OrderId, DeviceInfo)
VALUES
   (10, 'PageSize|BGColor|3000|V1.0'),
   (11, 'PageSize|BGColor|3000|V2.0'),
   (12, 'PageSize|BGColor|3000|V3.0')

声明:

SELECT OrderId, DeviceInfo, [Value]
FROM [Order] AS o
CROSS APPLY OPENJSON(CONCAT('["', REPLACE(o.DeviceInfo, '|', '","'), '"]')) AS j
WHERE o.OrderId = 10 AND j.[key] = '3'

结果:

OrderId DeviceInfo                 Value
----------------------------------------
10      PageSize|BGColor|3000|V1.0 V1.0

【讨论】:

确保您的字符串不包含任何逗号 (,)。 @F***Pijcke 逗号 (,) 不是问题。双引号 (") 是一个可能的问题,但如果 OP 使用 SQL Server 2017+,REPLACE(STRING_ESCAPE(o.DeviceInfo, 'json'), '|', '","') 可以解决此问题。

以上是关于交叉应用使用的子查询不返回结果的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL:多个存在返回不正确的结果

了解Mysql

NOT IN vs IN 不返回免费结果

SQL 中 EXISTS 与 NOT EXISTS

休眠查询不返回正确的结果

SQL 在视图中使用交叉引用两个表的结果创建列