STRINGinksLIT với dấu phân cách nhiều ký tự?


9

SQL Server 2016 đã giới thiệu STRINGinksLIT rất nhanh và là sự thay thế tuyệt vời cho bất kỳ người thực hiện tự chế nào sẽ triển khai trước năm 2016.

Thật không may, STRINGinksLIT chỉ hỗ trợ một dấu phân cách một ký tự, không phải lúc nào cũng đủ. Có ai biết về một triển khai tốt cho phép sử dụng nhiều ký tự trong dấu phân cách không?

Câu trả lời:


20

Chà, bạn luôn có thể sử dụng REPLACEđể thêm một dấu phân cách một ký tự vào đối số trước khi chuyển nó vào. Bạn chỉ cần chọn một ký tự không có khả năng / không thể xuất hiện trong dữ liệu thực tế. Trong ví dụ này, giả sử dữ liệu gốc của bạn sử dụng ba đường ống làm dấu phân cách; Tôi đã chọn một ký tự Unicode ngẫu nhiên để thay thế:

DECLARE 
  @olddelim nvarchar(32) = N'|||', 
  @newdelim nchar(1)     = NCHAR(9999); -- pencil (✏)

DECLARE @x nvarchar(max) = N'foo|||bar|||blat|||splunge';

SELECT * FROM STRING_SPLIT(REPLACE(@x, @olddelim, @newdelim), @newdelim);

Tôi viết blog về điều này chi tiết hơn ở đây:


Giải quyết một bình luận:

giải pháp xấu. Điều gì xảy ra nếu chuỗi gốc giống như 'abc | | pqr ||| rst | | 123' (động và có thể chứa bất cứ thứ gì). o / p mong muốn là 'abc | | pqr' và 'rst || 123' nhưng giải pháp của bạn sẽ cho 'abc' 'pqr' 'rst' '123'

Được rồi, hãy lấy đầu vào của bạn và xem liệu giải pháp của tôi có đầu ra sai.

DECLARE 
  @olddelim nvarchar(32) = N'|||', 
  @newdelim nchar(1)     = NCHAR(9999); -- pencil (✏)

DECLARE @x nvarchar(max) = N'abc||pqr|||rst||123';

SELECT * FROM STRING_SPLIT(REPLACE(@x, @olddelim, @newdelim), @newdelim);

Kết quả là:

abc||pqr
rst||123

Và không phải những gì bạn phải giả định (nhưng không kiểm tra) này:

abc
pqr
rst
123

Nếu dữ liệu của bạn nằm trong một bảng, bạn có thể tạo chế độ xem để bạn không phải đưa yếu tố biểu hiện đó vào tất cả các truy vấn của mình.


Nếu điều đó không hiệu quả, vì bạn có thể có một cây bút chì ( ) trong dữ liệu của mình và bạn không thể tìm thấy một ký tự trong 1.11,998 ký tự Unicode có sẵn không có trong bộ dữ liệu của bạn, bạn sẽ phải bỏ qua STRING_SPLIT(), vì nó được mã hóa cứng để chấp nhận một ký tự phân cách ký tự ( separator Is a single character expression).

Các lựa chọn thay thế đã được trả lời ở đây hàng chục lần trước đây , nhiều lần trước khi STRING_SPLIT()tồn tại. Những phương pháp đó vẫn hoạt động.

Tôi đi qua nhiều lựa chọn thay thế và cũng thảo luận về những hạn chế trong STRING_SPLIT()loạt bài này (tôi cũng thảo luận về lý do tại sao bạn có thể cân nhắc không làm điều này trong T-SQL bằng bất kỳ phương thức nào):


giải pháp xấu. Điều gì xảy ra nếu chuỗi gốc giống như 'abc | | pqr ||| rst | | 123' (động và có thể chứa bất cứ thứ gì). mong muốn o / p là 'abc || pqr' và 'đầu tiên || 123' nhưng giải pháp của bạn sẽ cho 'abc' 'pqr' 'đầu tiên' '123'
Jitendra Pancholi

@Jitendra Bạn đã đọc toàn bộ câu trả lời của tôi chưa? You just need to choose a character that is unlikely/impossible to appear in the actual data.Unicode có 1.11.998 ký tự có thể lựa chọn, nhưng nếu bạn thực sự không thể tìm thấy một ký tự duy nhất không có trong dữ liệu (hoặc không thể thay thế trong dữ liệu trước, trong ETL hoặc thứ gì đó), bạn sẽ cần một cách tiếp cận khác nhau (giống như nhiều cách tôi liên kết trong câu trả lời của tôi). Mong giải pháp tốt hơn của bạn.
Aaron Bertrand

Vẫn không phải là một cái tốt, bạn không thể chắc chắn 100% về dấu phân cách và cho rằng dấu phân cách này sẽ không phải là một phần của chuỗi.
Jitendra Pancholi


3
@JitendraPancholi Bạn đúng về mặt kỹ thuật , nhưng bạn không công bằng ở đây vì: 1) hạn chế là STRING_SPLIT, không phải là vấn đề cụ thể này, 2) câu hỏi này là về STRING_SPLIT, không hoạt động với các dấu phân cách đa ký tự nói chung, 3) trong thực tế, nó là an toàn để giả định rằng nhân vật nhất định sẽ không có mặt ở đó, ngược lại nó là dữ liệu chỉ xấu, 4) NCHAR(31) (kỷ lục separator) nên được an toàn vì đó là mục đích của nó, hoặc NCHAR(0)với , @newdelim COLLATE Latin1_General_100_BIN2);vì nếu U + 0000 (null) là trong bất kỳ chuỗi dữ liệu, sau đó có vấn đề lớn hơn!
Solomon Rutzky
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.