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

Đọc mẫu char, double, int từ chuỗi trong sql

Phiên bản cuối cùng (tôi hy vọng):

Vì sql server 2008 không hỗ trợ thứ tự theo mệnh đề trên của hàm tổng hợp, tôi đã thêm một cte khác để thêm chỉ mục hàng thay vì sum Tôi đã sử dụng trong phiên bản trước:

;WITH cteAllRows as
(
     SELECT Item, 
            ItemIndex, 
            CASE WHEN ISNUMERIC(Item) = 0 THEN 'String'
            WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0 THEN 'Double'
            WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 THEN 'Integer'
            END As DataType
     FROM dbo.SplitStrings_Numbers(@string, ',')
), cteAll as
(
    SELECT  Item, 
            DataType, 
            ItemIndex, 
            (
                SELECT COUNT(*)
                FROM cteAllRows tInner
                WHERE tInner.DataType = 'String'
                AND tInner.ItemIndex <= tOuter.ItemIndex
            ) As RowIndex
    FROM cteAllRows tOuter
)

Tất cả phần còn lại giống với phiên bản trước.

Cập nhật

Điều đầu tiên tôi đã làm là thay đổi hàm chia chuỗi thành một hàm dựa trên bảng kiểm đếm, để tôi có thể dễ dàng thêm số hàng vào đó. Vì vậy, nếu bạn chưa có bảng kiểm đếm, hãy tạo một bảng . Nếu bạn đang tự hỏi bảng kiểm đếm là gì và tại sao bạn cần nó, hãy đọc bài viết này của Jeff Moden :

SELECT TOP 10000 IDENTITY(int,1,1) AS Number
    INTO Tally
    FROM sys.objects s1       
    CROSS JOIN sys.objects s2 
ALTER TABLE Tally ADD CONSTRAINT PK_NumbersTest PRIMARY KEY CLUSTERED (Number)
GO

Sau đó, tạo hàm tách chuỗi dựa trên bảng kiểm đếm (lấy từ bài viết của Aaron nhưng thêm cột chỉ mục hàng):

CREATE FUNCTION dbo.SplitStrings_Numbers
(
   @List       NVARCHAR(MAX),
   @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN
   (
       SELECT   Item = SUBSTRING(@List, Number, CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number),
                ROW_NUMBER() OVER (ORDER BY Number) As ItemIndex
       FROM dbo.Tally
       WHERE Number <= CONVERT(INT, LEN(@List))
         AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
   );
GO

Bây giờ, Thủ thuật tôi đã sử dụng rất giống với mẹo trước, chỉ là bây giờ tôi đã thêm vào cte đầu tiên một cột mới mà tôi gọi là RowIndex, về cơ bản đó là tổng số chuỗi đang chạy, dựa trên hàng chỉ mục của tất cả các hàng:

 SELECT Item, 
        CASE WHEN ISNUMERIC(Item) = 0 THEN 'String'
        WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0 THEN 'Double'
        WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 THEN 'Integer'
        END As DataType,
        SUM(CASE WHEN ISNUMERIC(Item) = 0 THEN 1 END) OVER(ORDER BY ItemIndex) As RowIndex
 FROM dbo.SplitStrings_Numbers(@string, ',')

Nó cho tôi kết quả này:

Item       DataType RowIndex
---------- -------- -----------
ddd        String   1
1.5        Double   1
1          Integer  1
eee        String   2
2.3        Double   2
0          Integer  2
fff        String   3
1.2        Double   3
ggg        String   4
6.123      Double   4
1          Integer  4

Như bạn có thể thấy, bây giờ tôi có một số cho mỗi hàng, vì vậy từ giờ trở đi thật đơn giản:

;WITH cteAll as
(
     SELECT Item, 
            CASE WHEN ISNUMERIC(Item) = 0 THEN 'String'
            WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0 THEN 'Double'
            WHEN ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 THEN 'Integer'
            END As DataType,
            SUM(CASE WHEN ISNUMERIC(Item) = 0 THEN 1 END) OVER(ORDER BY ItemIndex) As RowIndex
     FROM dbo.SplitStrings_Numbers(@string, ',')
), cteString AS
(
    SELECT Item, RowIndex
    FROM cteAll
    WHERE DataType = 'String'
), cteDouble AS
(
    SELECT Item, RowIndex
    FROM cteAll
    WHERE DataType = 'Double'
), cteInteger AS
(
    SELECT Item, RowIndex
    FROM cteAll
    WHERE DataType = 'Integer'
)

SELECT  T1.Item As [String],
        T2.Item As [Double],
        T3.Item As [Integer]
FROM dbo.Tally 
LEFT JOIN cteString T1 ON T1.RowIndex = Number 
LEFT JOIN cteDouble T2 ON t2.RowIndex = Number 
LEFT JOIN cteInteger T3 ON t3.RowIndex = Number
WHERE COALESCE(T1.Item, T2.Item, T3.Item) IS NOT NULL

Điều đó đã cho tôi kết quả này:

String     Double     Integer
---------- ---------- ----------
ddd        1.5        1
eee        2.3        0
fff        1.2        NULL
ggg        6.123      1

Như bạn có thể thấy, các mục hiện đã được sắp xếp theo thứ tự ban đầu trong chuỗi.

Lần thử đầu tiên

Trước tiên, bạn phải chia chuỗi đó thành một bảng. Để làm điều đó, bạn nên sử dụng một chức năng do người dùng xác định. Bạn có thể chọn cái phù hợp nhất với mình từ Chuỗi phân chia của Aaron Bertrand đúng cách - hoặc cách tốt nhất tiếp theo bài báo.

Đối với phần trình diễn này, tôi đã chọn sử dụng SplitStrings_XML .

Vì vậy, trước tiên, hãy tạo hàm:

CREATE FUNCTION dbo.SplitStrings_XML
(
   @List       NVARCHAR(MAX),
   @Delimiter  NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING
AS
   RETURN 
   (  
      SELECT Item = y.i.value('(./text())[1]', 'nvarchar(4000)')
      FROM 
      ( 
        SELECT x = CONVERT(XML, '<i>' 
          + REPLACE(@List, @Delimiter, '</i><i>') 
          + '</i>').query('.')
      ) AS a CROSS APPLY x.nodes('i') AS y(i)
   );
GO

Bây giờ, hãy khai báo và khởi tạo biến:

declare @string nvarchar(max) = 'ddd,1.5,1,eee,2.3,0,fff,1.2,ggg,6.123,1'

Sau đó, Tạo 4 biểu thức bảng phổ biến - một cho tất cả các mục, một cho chuỗi, một cho gấp đôi và một cho số nguyên. Lưu ý việc sử dụng row_number() - nó sẽ được sử dụng sau này để kết hợp tất cả các kết quả lại với nhau:

;WITH AllItems as
(
    SELECT Item, ROW_NUMBER() OVER(ORDER BY (select null)) as rn
    FROM dbo.SplitStrings_XML(@string, ',')
)

, Strings as
(
    SELECT Item as StringItem, ROW_NUMBER() OVER(ORDER BY (select null))  as rn
    FROM dbo.SplitStrings_XML(@string, ',')
    WHERE ISNUMERIC(Item) = 0
), Doubles as 
(
    SELECT Item as DoubleItem, ROW_NUMBER() OVER(ORDER BY (select null))  as rn
    FROM dbo.SplitStrings_XML(@string, ',')
    WHERE ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) > 0
), Integers as
(
    SELECT Item as IntegerItem, ROW_NUMBER() OVER(ORDER BY (select null))  as rn
    FROM dbo.SplitStrings_XML(@string, ',')
    WHERE ISNUMERIC(Item) = 1 AND CHARINDEX('.', Item) = 0 
)

Sau đó, chọn từ việc kết hợp tất cả các biểu thức bảng phổ biến này. Lưu ý việc sử dụng COALESCE được xây dựng trong hàm để chỉ trả về các hàng có ít nhất một giá trị:

SELECT StringItem,  DoubleItem, IntegerItem
FROM AllItems A
LEFT JOIN Strings S ON A.rn = S.rn
LEFT JOIN Doubles D ON A.rn = D.rn
LEFT JOIN Integers I ON A.rn = I.rn
WHERE COALESCE(StringItem,  DoubleItem, IntegerItem) IS NOT NULL

Kết quả:

StringItem  DoubleItem  IntegerItem
----------  ----------  -----------
ddd         1.5         1
eee         2.3         0
fff         1.2         1
ggg         6.123       NULL


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nối các giá trị dựa trên ID

  2. Không sử dụng sp_depends trong SQL Server (nó không được dùng nữa)

  3. MS SSQL:Cách sử dụng trường hợp khi là tham số thực thi

  4. Cột văn bản không lưu trữ nhiều hơn 8000 ký tự

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