nvarchar 连接/索引/nvarchar(max) 莫名其妙的行为

2023-12-13

今天我在 SQL Server(2008R2 和 2012)中遇到了一个非常奇怪的问题。我正在尝试使用串联和结合来构建一个字符串select陈述。

我发现生成的字符串仅包含一个输入字符串 - 不是我所期望的所有输入字符串的串联结果。

我已经找到了解决方法,但我真的很想了解这里发生了什么以及为什么它没有给我预期的结果。有人可以向我解释一下吗?

http://sqlfiddle.com/#!18/d6228/1

根据要求,这里还有代码:

-- base table
create table bla (
    [id] int identity(1,1) primary key,
    [priority] int,
    [msg] nvarchar(max),
    [autofix] bit
)

-- table without primary key on id column
create table bla2 (
    [id] int identity(1,1),
    [priority] int,
    [msg] nvarchar(max),
    [autofix] bit
)

-- table with nvarchar(1000) instead of max
create table bla3 (
    [id] int identity(1,1) primary key,
    [priority] int,
    [msg] nvarchar(1000),
    [autofix] bit
)

-- fill the three tables with the same values
insert into bla ([priority], [msg], [autofix])
values (1, 'A', 0),
       (2, 'B', 0)

insert into bla2 ([priority], [msg], [autofix])
values (1, 'A', 0),
       (2, 'B', 0)

insert into bla3 ([priority], [msg], [autofix])
values (1, 'A', 0),
       (2, 'B', 0)
;
declare @a nvarchar(max) = ''
declare @b nvarchar(max) = ''
declare @c nvarchar(max) = ''
declare @d nvarchar(max) = ''
declare @e nvarchar(max) = ''
declare @f nvarchar(max) = ''

-- I expect this to work and generate 'AB', but it doesn't
select @a = @a + [msg]
    from bla
    where   autofix = 0
    order by [priority] asc

-- this DOES work: convert nvarchar(4000)
select @b = @b + convert(nvarchar(4000),[msg])
    from bla
    where   autofix = 0
    order by [priority] asc

-- this DOES work: without WHERE clause
select @c = @c + [msg]
    from bla
    --where autofix = 0
    order by [priority] asc

-- this DOES work: without the order by
select @d = @d + [msg]
    from bla
    where   autofix = 0
    --order by [priority] asc

-- this DOES work: from bla2, so without the primary key on id
select @e = @e + [msg]
    from bla2
    where   autofix = 0
    order by [priority] asc

-- this DOES work: from bla3, so with msg nvarchar(1000) instead of nvarchar(max)
select @f = @f + [msg]
    from bla3
    where   autofix = 0
    order by [priority] asc

select @a as a, @b as b, @c as c, @d as d, @e as e, @f as f

TLDR;这不是用于跨行连接字符串的记录/支持的方法。它有时有效,但有时会失败,因为这取决于您获得的执行计划。

而是使用以下有保证的方法之一

SQL Server 2017+

SELECT @a = STRING_AGG([msg], '') WITHIN GROUP (ORDER BY [priority] ASC)
FROM bla
where   autofix = 0

SQL Server 2005+

SELECT @a = (SELECT [msg] + ''
             FROM   bla
             WHERE  autofix = 0
             ORDER  BY [priority] ASC
             FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)') 

背景

The 知识库文章范德诺斯已经链接确实包括该行

聚合串联查询的正确行为是 不明确的。

但随后提供了一种似乎确实表明确定性行为是可能的解决方法,从而使水变得有点浑浊。

为了达到预期的综合效果 连接查询,应用任何 Transact-SQL 函数或表达式 SELECT 列表中的列而不是 ORDER BY 子句中的列。

您有问题的查询不会将任何表达式应用于ORDER BY clause.

2005年的文章SQL Server 中的排序保证...是否说明

出于向后兼容性的原因,SQL Server 提供了支持 最顶层的 SELECT @p = @p + 1 ... ORDER BY 类型的赋值 范围。

在连接按预期工作的计划中,计算标量具有表达式[Expr1003] = Scalar Operator([@x]+[Expr1004])出现在排序上方。

在无法工作的计划中,计算标量出现在排序下方。正如中所解释的这个连接项目从 2006 年开始,当表达@x = @x + [msg]出现在对每行进行评估的排序下方,但所有评估最终都使用预分配值@x. In 另一个类似的连接项目从2006年开始,微软的回应就提到“解决”这个问题。

Microsoft 对所有后续 Connect 项目中有关此问题(并且有很多)的回复均指出,这根本无法得到保证

实施例1

我们不保证连接的正确性 查询(例如在数据检索中使用变量赋值) 具体顺序)。 SQL Server 2008 中的查询输出可能会发生变化 取决于计划选择、表格中的数据等。您不应该 即使语法允许您始终依赖此工作 编写一个 SELECT 语句,将有序行检索与 变量赋值。

实施例2

您所看到的行为是设计使然的。使用赋值运算 (本例中的串联)在带有 ORDER BY 子句的查询中 未定义的行为。这可能会随着版本的不同而改变,甚至 由于查询计划的更改,在特定服务器版本内。 即使有解决方法,您也不能依赖此行为。看 有关更多详细信息,请参阅以下知识库文章:
http://support.microsoft.com/kb/287515唯一有保证的 机制如下:

  1. 使用游标按特定顺序循环遍历行并连接值
  2. 使用 ORDER BY 进行 xml 查询来生成连接值
  3. 使用 CLR 聚合(这不适用于 ORDER BY 子句)

实施例3

您所看到的行为实际上是设计使然的。这与 SQL 是一种集合操作语言。 SELECT 中的所有表达式 列表(这也包括作业)不能保证 对每个输出行只执行一次。其实就是SQL查询 优化器努力尽可能少地执行它们。这 当您计算值时将给出预期结果 变量基于表中的某些数据,但是当您的值 分配取决于同一变量的先前值, 结果可能会出乎意料。如果查询优化器移动了 表达式到查询树中的不同位置,可能会得到 评估次数较少(或仅评估一次,如您的示例之一)。这 这就是为什么我们不建议使用“迭代”类型分配 计算合计值。我们发现基于 XML 的解决方法...通常适用于 顾客

实施例4

即使没有 ORDER BY,我们也不能保证 @var = @var + 将为任何语句生成串联值 影响多行。表达式的右侧可以 在查询执行期间评估一次或多次 我所说的行为取决于计划。

实施例5

使用 SELECT 语句进行变量赋值是一种专有语法 (仅限 T-SQL)如果行为未定义或依赖于计划 产生多行。如果您需要进行字符串连接 然后使用 SQLCLR 聚合或基于 FOR XML 查询的串联或 其他关系方法。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

nvarchar 连接/索引/nvarchar(max) 莫名其妙的行为 的相关文章

  • 我可以根据多列删除数据库重复项吗?

    I 不久前问过这个问题 https stackoverflow com questions 4952250 how to delete duplicates from a database table based on a certain
  • 将 MSSQL 中用于 Web 制图的投影(Leaflet、Openlayer、OpenStreetMaps、GoogleAPI...)更改为 WSG48 或任何其他格式

    我在 MSSQL 服务器中有一些像这样的 WKT WKB 数据 并希望借助 leaflet Openlayer OpenStreetMaps 或 GoogleAPI 将它们显示在地图上 我的数据如下所示 POLYGON 1736946 09
  • TSQL - 生成文字浮点值

    我理解比较浮点数时遇到的许多问题 并对它们在这种情况下的使用感到遗憾 但我不是表格作者 只有一个小障碍需要克服 有人决定使用浮点数 就像您期望使用 GUID 一样 我需要检索具有特定浮点值的所有记录 sp help MyTable Colu
  • 如何连续添加起始行和下一行的值

    我只想创建一个 sql 查询 结果就像图片上的那样 类似于 SQL 中的斐波那契数列 Ex Column 1 10 则 Result 列的值为 Result 10 因为这是第一行 然后假设column1第二行的值为50 那么Result第二
  • 使用 MS Access 链接表连接到 SQL Server 后端时是否可能发生 SQL 注入

    我一直在对此进行一些研究 但到目前为止还是一片空白 情况是这样的 我正在开发一个链接到 SQL Server 后端的 MS Access 前端 我在某种程度上使用 Access 中的链接表 表单访问 SQL DB 这样 当用户更新表单中的值
  • 在对象数组内的特定 JSON 值上创建索引

    假设我的表中有一个 varchar 列 其结构如下 Response DataArray Type Address Value 123 Fake St Type Name Value John Doe 我想在 DataArray 数组元素的
  • 获取在任何日期创建的表的列表?

    我遇到了这样的情况 我想查找我在 2012 年 9 月 14 日 2012 年 9 月 14 日 在 sql server 上创建的表 是否有任何查询会列出在此日期创建的这些表 SELECT FROM sys tables WHERE cr
  • Entity Framework 6(代码优先)实体版本控制和审计

    我正在考虑将 Entity Framework 6 1 1 与 SQL Server 2008 R2 一起使用 目前 我正在使用代码优先的 EF 功能创建模型和数据库 我的基本用例是创建一个特定实体的所有更改的日志 ID是关键栏 以帮助审核
  • 使用存储过程中的 Select 查询将单个变量分配给多行

    我的查询是使用 Select 将单个变量分配给多行 存储过程中的查询 例如 我从 Employee 表中获取 10 个 比如 1 到 10 个员工 ID 声明 id int select id EmpId from Employee sel
  • 插入记录后如何从SQL Server获取Identity值

    我在数据库中添加一条记录identity价值 我想在插入后获取身份值 我不想通过存储过程来做到这一点 这是我的代码 SQLString INSERT INTO myTable SQLString Cal1 Cal2 Cal3 Cal4 SQ
  • 插入具有只读主键列的表

    我正在使用一个使用 sql server 数据库的应用程序 我试图在表中插入一行 如下所示 该表有一个主键 prodNum 这是自动生成的密钥 当我尝试向表中插入一行时 如下所示 在行中intResult oSglProdTableAdap
  • 通过 C# SqlCommand 执行合并语句不起作用

    我正在第一次尝试使用临时表和MERGE语句通过更新 SQL 表SqlCommandC 中的对象 我正在开发的程序旨在首先将大量记录 最多 20k 导出到 Excel 电子表格中 然后 用户可以搜索并替换特定值 并根据需要更新任意多记录中的任
  • 可以有一个带有可变列的表吗?

    这可能是一个愚蠢的问题 但这里是 是否可以创建一个能够包含具有可变列数和自定义列名称的行的动态表 我浏览过 EAV 建模 但看起来很沉重 现实生活中的例子可能是这样的 假设我有一个客户登记册 但每个客户可能需要输入不同的信息 根据您要输入的
  • ALTER TABLE 语句与 FOREIGN KEY 约束冲突

    为什么要添加外键tblDomare表导致此错误 ALTER TABLE 语句与 FOREIGN KEY 约束 FK tblDomare PersN 5F7E2DAC 冲突 冲突发生在数据库 almu0004 表 dbo tblBana 列
  • 如何在 SQL Server 中不循环更新列?

    出于性能角度的考虑 我只需要删除循环并使用一些联接或其他解决方案来更新 Result 表中的数据并获得循环返回的相同结果 标量函数 CREATE FUNCTION MultiplyerScl a INT b INT RETURNS INT
  • SQL Server 中的 FIFO 查询

    我正在构建一个库存管理应用程序c with SQL server 我想做一个FIFO从我的表查询 我以可变价格购买了相同的产品 之后我卖掉了其中一些 我想根据 先进先出 进行查询BatchDate柱子 所以我想通过PurchasePrice
  • 计算2个日期之间每个日期的记录数

    我必须创建一个查询来返回多轴图表的结果 我需要计算为 2 个日期之间的每个日期创建的 ID 数量 我试过这个 DECLARE StartDate datetime2 7 11 1 2020 EndDate datetime2 7 2 22
  • 如何向 SQL 连接字符串添加自定义属性?

    我想在 SqlServer 连接字符串中添加一些自定义属性 如下所示 Integrated Security SSPI Extended Properties SomeAttr SomeValue Persist Security Info
  • 为什么 ISNUMERIC('.') 返回 1?

    最近我在 SQL Server 中使用 ISNUMERIC 时遇到了一个问题 导致找到了这段代码 SELECT ISNUMERIC 这会返回 1 如 true 所示 难道不应该像 false 一样返回 0 吗 See Numeric 损坏了
  • 如何使用 SQL 查询创建逗号分隔的列表?

    我有 3 个表 名为 应用程序 ID 名称 资源 id 名称 应用程序资源 id app id resource id 我想在 GUI 上显示所有资源名称的表格 在每一行的一个单元格中 我想列出该资源的所有应用程序 以逗号分隔 所以问题是

随机推荐

  • 有反向映射功能吗?

    在 clojure 中 您可以将函数映射到值序列 是否有一个内置函数可以将单个值作为参数映射到一系列函数 map inc 1 2 3 4 gt 2 3 4 5 reverse map inc dec str 1 gt 2 0 1 rever
  • 什么是spark.python.worker.memory?

    谁能给我更准确地描述这个 Spark 参数以及它如何影响程序执行 我无法从文档中确切地看出这个参数 在幕后 的作用 该参数影响 Python 工作线程的内存限制 如果Python工作进程的RSS大于内存限制 那么它会将数据从内存溢出到磁盘
  • setNeedsLayout 与 setNeedsUpdateConstraints 和 layoutIfNeeded 与 updateConstraintsIfNeeded

    我知道自动布局链基本上由 3 个不同的过程组成 更新约束 布局视图 这是我们计算帧的地方 display 我不完全清楚的是两者之间的内在区别 setNeedsLayout and setNeedsUpdateConstraints 来自苹果
  • 使用 python 和请求进行 Instagram 身份验证

    我需要为我的项目创建 Instagram 登录表单 我已经编写了这段代码 但它不能正常工作 我需要在请求后获取 sessionid cookie def authorize inst url https www instagram com
  • 如何合并两个数据库,具有相同的数据,但具有不同的主键,且没有重复的字段?

    我有两个 mdb 文件 如果需要的话 我还可以将其转换为 MySQL 数据库 如何将这两个不同的数据库合并为一个 这个想法是从两个数据库获取所有信息并将其合并为一个 而不复制任何客户端 问题是两个bds都有相同的客户端和不同的客户端 但是客
  • 防伪令牌适用于用户“”,但当前用户是“用户名”

    我正在构建一个单页应用程序并遇到防伪令牌问题 我知道为什么会出现这个问题 只是不知道如何解决 当发生以下情况时我收到错误 未登录用户加载对话框 带有生成的防伪令牌 用户关闭对话框 用户登录 用户打开相同的对话框 用户在对话框中提交表单 防伪
  • nuspec contentFiles 未添加到项目中

    我有一个网络项目 mvc5 项目 json inside 另外 我有一个 nuget 包 在这个包中 除了 dll 引用之外 我有一些内容文件 cshtml 文件 css javascript 等 有 2 个目标需要实现 将包安装到项目后
  • Python 硒和验证码

    我有一个抓取机器人 每当遇到验证码时我都想停止它 以免惹恼网站 但是selenium找不到它 driver find element by xpath id recaptcha anchor 这是 chrome 给我的 xpath ERRO
  • Tailwind CSS,不尊重类优先级

    我有以下元素 td class td 它的所有类名都是通过组件自动生成的 除了最后一个 min w 0 Since min w 0是列出的最后一个类名 我希望它能够覆盖min w 10rem 列出的第 1 类名称 然而 由于某种原因 min
  • 将数据框中的每一列转换为单独的数据框

    假设我有一个包含 10 列的数据框 其中 10 列中的每一列代表一个单独的时间序列 我想将每个时间序列 或数据帧的每一列 存储在单独的数据帧中 我尝试使用 allocate columnname df i 其中 i 是 for 循环中的变量
  • 在android中的EditText上输入时如何过滤ListView数据

    我有一个ListView and a EditText 如何在输入内容时过滤 ListView 数据EditText Add TextWatcher to EditText addTextChangedListener In onTextC
  • 将收件箱和已发送短信与所有短信区分开来

    我正在开发一个 Android 应用程序 在我的应用程序中 我必须列出所有对话 并且我完成了该部分 每个对话都包含发送到该号码的所有短信 所以我必须将收件箱和已发送短信与所有短信区分开来 我知道以下 api 可用于查找收件箱和已发送短信 c
  • 通过悬停另一个元素使一个元素可见(不带 :hover-property)

    好吧 问题是这样的 我有这三个 DIV div div div div div div 这三个 DIV 不可见 display none 位于页面上完全不同的位置 div div div div div div 我想做的是 如果我将鼠标悬停
  • 如何获得类型依赖于隐式参数的方法参数?

    trait JsonOps J type ObjectFields def partitionObjectFields fields ObjectFields fieldNames List String ObjectFields Obje
  • 计算年百分比(需要继承代码的一些帮助)

    我正在制作一个应用程序 为客户提供大致的贷款报价 稍后由其他后台系统计算 我从我们为其制作计算器的金融公司收到了一些代码 我的问题是我不理解计算年百分比率 包括启动费和月费 的代码部分 他们可能正在使用这种方法 但我不能真正告诉 http
  • 如何在 Telegram 中从 Bot 发送自定义表情符号

    我正在尝试使用 Telegram API 发送 custom emoji消息实体 object 我尝试这样做的方法如下 const message ctx sendMessage text message entities type cus
  • “关闭”流?

    我正在从 java 读取文本BufferedReader像这样 Stream continually reader readLine takeWhile case null gt reader close false case gt tru
  • 修剪 NSString 末尾的空格

    我需要删除字符串末尾的空格 我怎样才能做到这一点 示例 如果字符串是 Hello 它必须成为 Hello 摘自这里的答案 https stackoverflow com a 5691567 251012 NSString stringByT
  • 如何使用两列上的 WHERE 子句加速 MySQL 查询?

    我试图通过两列上的 WHERE 子句来加速对大型表的查询 据我所知 MySQL 仅使用 ALERT ID 列 有没有办法使用两个索引重写此查询 SHOW INDEX 和 EXPLAIN 输出如下 show index from alert
  • nvarchar 连接/索引/nvarchar(max) 莫名其妙的行为

    今天我在 SQL Server 2008R2 和 2012 中遇到了一个非常奇怪的问题 我正在尝试使用串联和结合来构建一个字符串select陈述 我发现生成的字符串仅包含一个输入字符串 不是我所期望的所有输入字符串的串联结果 我已经找到了解