Sqlserver
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Sqlserver

hành vi nối nvarchar / chỉ mục / nvarchar (tối đa) không thể giải thích được

TLDR; Đây không phải là phương pháp được tài liệu hóa / hỗ trợ để nối các chuỗi giữa các hàng. Nó đôi khi hoạt động nhưng cũng đôi khi không thành công vì nó phụ thuộc vào kế hoạch thực thi bạn nhận được.

Thay vào đó, hãy sử dụng một trong các cách tiếp cận được đảm bảo sau đây

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)') 

Bối cảnh

Bài viết KB đã được VanDerNorth liên kết không bao gồm dòng

Hành vi chính xác cho truy vấn nối tổng hợp được xác định.

nhưng sau đó tiếp tục làm bùn nước một chút bằng cách cung cấp một giải pháp có vẻ như cho thấy hành vi xác định là có thể.

Để đạt được kết quả mong đợi từ một truy vấn tổng hợp, hãy áp dụng bất kỳ hàm hoặc biểu thức Transact-SQL nào cho các cột trong danh sách CHỌN thay vì trong mệnh đề ORDER BY.

Truy vấn có vấn đề của bạn không áp dụng bất kỳ biểu thức nào cho các cột trong ORDER BY mệnh đề.

Bài báo 2005 Các đảm bảo về thứ tự trong SQL Server ... hiện trạng

Vì lý do tương thích ngược, SQL Server cung cấp các thiết kế hỗ trợ kiểu SELECT @p =@p + 1 ... ORDER BY ở top-mostscope.

Trong các phương án mà phép nối hoạt động như bạn mong đợi, phép tính vô hướng có biểu thức [Expr1003] = Scalar Operator([@x]+[Expr1004]) xuất hiện phía trên loại.

Trong kế hoạch mà nó không hoạt động, tính toán vô hướng xuất hiện bên dưới sắp xếp. Như đã giải thích trong mục kết nối này từ năm 2006 khi biểu thức @x = @x + [msg] xuất hiện bên dưới sắp xếp mà nó được đánh giá cho mỗi hàng nhưng tất cả các đánh giá đều sử dụng giá trị gán trước của @x . Trong một Mục kết nối tương tự khác từ năm 2006, phản hồi từ Microsoft đã nói về việc "khắc phục" sự cố.

Phản hồi của Microsoft trên tất cả các mục Connect sau này về vấn đề này (và còn nhiều) cho biết điều này chỉ đơn giản là không được đảm bảo

Ví dụ 1

chúng tôi không đưa ra bất kỳ đảm bảo nào về tính đúng đắn của các truy vấn nối (như sử dụng các phép gán biến với truy xuất dữ liệu theo thứ tự cụ thể). Kết quả truy vấn có thể thay đổi trong SQL Server 2008 tùy thuộc vào lựa chọn gói, dữ liệu trong bảng, v.v. Bạn không nên làm việc này một cách nhất quán mặc dù cú pháp cho phép bạn viết câu lệnh SELECT kết hợp truy xuất các hàng có thứ tự với phép gán có thể thay đổi.

Ví dụ 2

Hành vi bạn đang thấy là do thiết kế. Sử dụng các phép toán gán (nối trong ví dụ này) trong các truy vấn với hành vi đã xác định sẵn mệnh đề ORDER BY. Điều này có thể thay đổi từ bản phát hành sang bản phát hành hoặc thậm chí trong một phiên bản máy chủ cụ thể do những thay đổi trong kế hoạch truy vấn. Bạn không thể dựa vào hành vi này ngay cả khi có các giải pháp thay thế. Xem bài viết dưới KB để biết thêm chi tiết:
http://support.microsoft.com/kb/287515 Cơ chế được đảm bảo DUY NHẤT như sau:

  1. Sử dụng con trỏ để lặp qua các hàng theo thứ tự cụ thể và nối các giá trị
  2. Sử dụng cho truy vấn xml với ORDER BY để tạo các giá trị được nối
  3. Sử dụng tổng hợp CLR (điều này sẽ không hoạt động với mệnh đề ORDER BY)

Ví dụ 3

Hành vi bạn đang thấy thực sự là do thiết kế. Điều này liên quan đến việcSQL là một ngôn ngữ thao tác thiết lập. Tất cả các biểu thức trong danh sách CHỌN (và điều này cũng bao gồm cả các phép gán) không được đảm bảo sẽ được thực thi chính xác một lần cho mỗi hàng đầu ra. Trên thực tế, SQL queryoptimizer cố gắng thực thi chúng ít lần nhất có thể. Điều này sẽ cung cấp kết quả mong đợi khi bạn đang tính toán giá trị của biến dựa trên một số dữ liệu trong bảng, nhưng khi giá trị mà bạn đang gán phụ thuộc vào giá trị trước đó của cùng một biến, kết quả có thể khá bất ngờ. Nếu trình tối ưu hóa truy vấn di chuyển biểu thức đến một vị trí khác trong cây truy vấn, nó có thể được đánh giá ít lần hơn (hoặc chỉ một lần, như trong một trong các ví dụ của bạn). Đây là lý do tại sao chúng tôi khuyên bạn không nên sử dụng các phép gán loại "lặp đi lặp lại" để tính toán các giá trị tổng hợp. Chúng tôi nhận thấy rằng các cách giải quyết dựa trên XML ... thường hoạt động tốt cho khách hàng

Ví dụ 4

Ngay cả khi không có ORDER BY, chúng tôi không đảm bảo rằng @var =@var + sẽ tạo ra giá trị được nối cho bất kỳ câu lệnh nào ảnh hưởng đến nhiều hàng. Phía bên phải của biểu thức có thể được đánh giá một lần hoặc nhiều lần trong quá trình thực thi truy vấn và hành vi như tôi đã nói là phụ thuộc vào kế hoạch.

Ví dụ 5

Phép gán biến với câu lệnh SELECT là một cú pháp độc quyền (chỉ dành cho T-SQL) trong đó hành vi là không xác định hoặc phụ thuộc vào kế hoạch nếu nhiều hàng được tạo ra. Nếu bạn cần thực hiện nối chuỗi, hãy sử dụng tổng hợp SQLCLR hoặc kết nối dựa trên truy vấn FOR XML với các phương thức quan hệ khác.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chèn các hàng vào bảng chỉ với một cột IDENTITY

  2. OBJECTPROPERTY () so với OBJECTPROPERTYEX () trong SQL Server:Sự khác biệt là gì?

  3. Chuyển đổi giữa các kiểu dữ liệu ngày và giờ trong SQL Server (Ví dụ T-SQL)

  4. Cách thay đổi kiểu dữ liệu cột trong cơ sở dữ liệu SQL mà không làm mất dữ liệu

  5. “Truy vấn không được phép trong Waitfor” Lỗi 101 trong SQL Server