亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

nvarchar串聯/索引/nvarchar(Max)令人費解的行為

nvarchar串聯/索引/nvarchar(Max)令人費解的行為

30秒到達戰場 2019-06-29 10:45:59
nvarchar串聯/索引/nvarchar(Max)令人費解的行為我今天在SQLServer中遇到了一個非常奇怪的問題(2008R2和2012)。我試圖使用連接與select聲明。我已經找到了解決辦法,但我真的很想了解這里發生了什么,以及為什么它沒有給我預期的結果。有人能給我解釋一下嗎?http://sqlfiddle.com/#!6/7438a/1應要求,這里的代碼也是:-- base tablecreate table bla (     [id] int identity(1,1) primary key,     [priority] int,     [msg] nvarchar(max),     [autofix] bit)-- table without primary key on id columncreate table bla2 (     [id] int identity(1,1),     [priority] int,     [msg] nvarchar(max),     [autofix] bit)-- table with nvarchar(1000) instead of maxcreate table bla3 (     [id] int identity(1,1) primary key,     [priority] int,     [msg] nvarchar(1000),     [autofix] bit)-- fill the three tables with the same valuesinsert 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'tselect @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 clauseselect @c = @c + [msg]     from bla    --where autofix = 0     order by [priority] asc-- this DOES work: without the order byselect @d = @d + [msg]     from bla    where   autofix = 0     --order by [priority] asc-- this DOES work: from bla2, so without the primary key on idselect @e = @e + [msg]
查看完整描述

2 回答

?
絕地無雙

TA貢獻1946條經驗 獲得超4個贊

這個KB文章由VanDerNorth鏈接的已經包含了行

未定義聚合連接查詢的正確行為。

但接下來,通過提供一個似乎確實表明確定性行為是可能的解決方案,把水弄得有點渾濁。

為了實現聚合連接查詢的預期結果,請將任何Transact-SQL函數或表達式應用于SELECT列表中的列,而不是ORDERBY子句中的列。

有問題的查詢不會將任何表達式應用于ORDER BY條款。

2005年文章SQL Server中的訂單保證。狀態

出于向后兼容性的原因,SQLServer提供了對SELECT@p=@p+1類型賦值的支持.在最高的范圍內訂購。

在連接工作的計劃中,與表達式一起計算標量。[Expr1003] = Scalar Operator([@x]+[Expr1004])出現在該類別的上方。

在無法工作的計劃中,計算標量出現在排序下面。如在此連接項從2006年開始@x = @x + [msg]顯示在為每一行計算的排序下面,但所有計算結果都使用@x..在……里面另一個類似的連接項從2006年起,微軟的回應就談到“解決”這個問題。

Microsoft對有關此問題的所有后續連接項的響應(還有許多)指出,這一點根本無法保證

例1

我們不保證連接查詢的正確性(比如使用變量賦值和特定順序的數據檢索)。SQL Server 2008中的查詢輸出可以根據計劃選擇、表中的數據等進行更改。即使語法允許您編寫一個SELECT語句,將有序的行檢索與變量賦值混合在一起,您也不應該一直依賴這種工作。

例2

你所看到的行為是故意的。在帶有ORDERBY子句的查詢中使用賦值操作(在本例中為串聯)具有未定義的行為。由于查詢計劃的更改,這可能在不同版本之間發生更改,甚至在特定的服務器版本中也會發生變化。即使有解決辦法,也不能依賴這種行為。有關更多細節,請參見下面的KB文章:
http://support.microsoft.com/kb/287515唯一的保障機制如下:

  1. 使用游標按特定順序遍歷行,并將值連接起來。
  2. 用于帶有Orderby的xml查詢,以生成級聯的值
  3. 使用CLR聚合(這不適用于ORDERBY子句)

例3

你所看到的行為實際上是故意的。這與SQL是一種集操作語言有關。SELECT列表中的所有表達式(這也包括賦值)不能保證對每個輸出行精確執行一次。實際上,SQL查詢優化器試圖盡可能少地執行它們。當您根據表中的某些數據計算變量的值時,這將給出預期的結果,但是當您要分配的值取決于同一變量的前一個值時,結果可能是非常出乎意料的。如果查詢優化器將表達式移動到查詢樹中的不同位置,則可能會得到較少的計算次數(或者只得到一次,如您的一個示例所示)。這就是為什么我們不建議使用“迭代”類型賦值來計算聚合值的原因。我們發現基于XML的解決方案.通常為客戶服務。

例4

即使沒有ORDERBY,我們也不能保證@var=@var+將為任何影響多行的語句生成級聯值。表達式的右側可以在查詢執行期間計算一次或多次,而且正如我所說的行為依賴于計劃。

例5

帶有SELECT語句的變量賦值是一種專有語法(僅為T-SQL),在這種語法中,行為是未定義的,如果產生多個行,則計劃依賴。如果需要進行字符串連接,則使用SQLCLR聚合或用于基于XML查詢的連接或其他關系方法。


查看完整回答
反對 回復 2019-06-29
  • 2 回答
  • 0 關注
  • 1042 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號