Sql-Server

拆分字元串函式

  • November 3, 2015

我對 Aaron Bertrand在這裡推薦的這個拆分字元串函式有疑問。

有了它,您可以提取兩個斜線之間的資訊。現在,如果我不僅要提取像伺服器名稱這樣的一條資訊,還要提取像星期幾這樣的第二條資訊。為了在一個結果集中獲取該資訊,我將如何重寫程式碼?

這是我的數據範例

E:\BaseData\RUK\HPP_Conversion_Detail\hpp_conversion_detail_report_2015_11_02.csv
E:\BaseData\RUK\Manual_Review\manual_review_report_2015_11_01.csv
E:\BaseData\RUK\Disputes\dispute_report_2015_11_01.csv
E:\BaseData\RSE\HPP_Conversion_Detail\hpp_conversion_detail_report_2015_11_02.csv
E:\BaseData\RSE\Manual_Review\manual_review_report_2015_11_01.csv
E:\BaseData\RSE\Disputes\dispute_report_2015_11_01.csv

我對第二個和第三個斜線以及第三個和第四個斜線之間的所有內容感興趣。Geoff 的建議是個好主意。然後我得到了行中的結果。是否可以在其他列中返回結果?

謝謝!

使用 Aaron Bertrand在這裡推薦的。

CREATE FUNCTION dbo.SplitStringsOrdered
(
   @List       NVARCHAR(2000),
   @Delimiter  NVARCHAR(32)
)
RETURNS TABLE
AS
   RETURN 
   (
     SELECT rn = ROW_NUMBER() OVER (ORDER BY Number), Item 
       FROM (SELECT Number, Item = LTRIM(RTRIM(SUBSTRING(@List, Number, 
         CHARINDEX(@Delimiter, @List + @Delimiter, Number) - Number)))
       FROM (SELECT ROW_NUMBER() OVER (ORDER BY [object_id])
         FROM sys.all_objects) AS n(Number)
       WHERE Number <= CONVERT(INT, LEN(@List))
       AND SUBSTRING(@Delimiter + @List, Number, LEN(@Delimiter)) = @Delimiter
     ) AS y);

還有你的範例數據

CREATE TABLE #x
(filepath NVARCHAR(2000));

INSERT #x VALUES
('E:\BaseData\RUK\HPP_Conversion_Detail\hpp_conversion_detail_report_2015_11_02.csv'),
('E:\BaseData\RUK\Manual_Review\manual_review_report_2015_11_01.csv'),
('E:\BaseData\RUK\Disputes\dispute_report_2015_11_01.csv'),
('E:\BaseData\RSE\HPP_Conversion_Detail\hpp_conversion_detail_report_2015_11_02.csv'),
('E:\BaseData\RSE\Manual_Review\manual_review_report_2015_11_01.csv'),
('E:\BaseData\RSE\Disputes\dispute_report_2015_11_01.csv')

然後你可以執行類似的東西

SELECT * FROM  #x x
CROSS   APPLY dbo.SplitStringsOrdered(x.filepath, '\') sso
WHERE sso.rn = 3

並退出第三部分。

有幾種方法可以到達多個部分。您可以從最後刪除 WHERE sso.rn = 3 ,但數據會分散在許多可能不適合您的行上。

使用子查詢可能對您有用。

SELECT *
, Part3 = (SELECT sso.Item FROM dbo.SplitStringsOrdered(x.filepath, '\') sso
WHERE sso.rn = 3) 
, Part5 = (SELECT sso.Item FROM dbo.SplitStringsOrdered(x.filepath, '\') sso
WHERE sso.rn = 5) 
FROM  #x x

程式碼突出顯示上方的警告錯誤地認為 \ 轉義了它後面的單引號,這在 SSMS/SQL-server 中實際上並非如此,除非您要求這種行為。

如果你想要一切,使用 MIN Pivot 的 hack 可能是最適合你的。

;
WITH    splits
         AS (
              SELECT   x.filepath
                     , sso.rn
                     , sso.Item
              FROM     #x x
              CROSS APPLY dbo.SplitStringsOrdered(x.filepath, '\') sso
            )
            SELECT * 
            FROM
            (  SELECT  splits.filepath
         , splits.rn
         , splits.Item
   FROM    splits   )  AS src
   PIVOT ( MIN(Item)
   FOR rn IN ([1],[2],[3],[4],[5])
          )   AS pvt

但這最終看起來有點瘋狂,實際上並不像看起來那樣靈活或有用,而且總 MIN 很醜陋。

因此,您可以在沒有樞軸黑客和更多子查詢的情況下混合使用兩者。

;WITH   splits
         AS (
              SELECT   x.filepath
                     , sso.rn
                     , sso.Item
              FROM     #x x
              CROSS APPLY dbo.SplitStringsOrdered(x.filepath, '\') sso
            )
   SELECT  x.filepath
         , (
             SELECT s.Item FROM splits s WHERE s.rn = 2 AND s.filepath = x.filepath
           )
         , (
             SELECT s.Item FROM splits s WHERE s.rn = 3 AND s.filepath = x.filepath
           )
         , (
             SELECT    s.Item
             FROM      splits s
             WHERE     s.rn = (
                                SELECT MAX (splits.rn) FROM splits
                              )
                       AND s.filepath = x.filepath
           )
   FROM    #x x

引用自:https://dba.stackexchange.com/questions/119813