2017-10-11 48 views
1

我有一個字符串列,其由$$字符分隔象下面這樣:SQL Server的拆分價值爲

BOB$$"DOG"$$"BROWN"$$"9"$$"4"$$"Latest"$$$$$$"small. 
EVA$$"CAT"$$"BLACK"$$"1"$$"4"$$$$"Mouse"$$"Milk"$$small. 

我想使用後的功能得到:更新/插入選擇/ SSIS映射

表像這樣:

Column1 Column2 Column3 Column4 Column5 Column6  Column7 Column8  Column9 
BOB  "DOG"  "BROWN" "9"  "4" "Lat,est" NULL  NULL  small. 
EVA  "CAT"  "BLACK" "1"  "4"  NULL  "Mouse" "Milk"  small. 

我可以做9行與功能更新/插入選擇以獲得結果? 我可以創建兩個表;第一個表格包含單列,第二個表格包含9列或10列。

我需要100 +行的通用解決方案。以上兩行僅僅是例子。

我覺得像這種類型的代碼繼續:

SELECT [Column0] 
     ,LEFT([Column0], CHARINDEX('$$', [Column0]) - 1) AS [name] 

FROM [dbo].[tablename] 
+0

是您的數據平面文件源?你真的打算把封閉的報價作爲數據嗎? – Filburt

+0

@filburt是的是平面文件的CSV但每天超過100我使用SSIS,但我有轉換1250語言到1252的問題Visual Studio的SQL服務器有問題...對我來說容易我認爲是這種方式 – Tester

+0

如果您正在使用SSIS,配置平面文件數據源應該很容易:您可以設置所需的代碼頁並指定列分隔符$$,並保留引號。我不希望任何手寫代碼的需要。如果您還沒有嘗試過,我建議您在SSIS中創建一個數據流,並探索Flat File數據源提供的選項。 – Filburt

回答

1

你是在正確的軌道上。使用SSIS導入平面文件時,我們通常將所有內容導入爲varchar數據類型列表(稱爲分段表),然後檢查列值以獲取數據類型一致性。這使我們可以導入所有內容,而不會丟失數據,並給予清理數據的機會。

方法1:對於您的情況,您可以在SSIS數據流任務源中使用$$作爲列分隔符。 SSIS不關心標題列順序或名稱。您可以在標題名稱中包含任何內容,如列1,列2等。 在此方法中,您將數據從文件導入到9列表中。如果某些行中的列數更少/更多,則此方法將失敗。

方法2:您將所有內容作爲單列導入到varchar臨時表(1)中。 從這裏您將所有列拆分並插入到9列(NULLable)的另一個varchar staging表(2)中,然後在將數據移動到數據類型列表之前進行數據驗證。可在方法2

create table staging_tbl_single_row (datarow varchar(max)) 
insert into staging_tbl_single_row values 
('BOB$$"DOG"$$"BROWN"$$"9"$$"4"$$"Latest"$$$$$$"small.'), 
('EVA$$"CAT"$$"BLACK"$$"1"$$"4"$$$$"Mouse"$$"Milk"$$small.') 

; with cte as 
(
    select 
    row_number() over (order by (select NULL)) as column1, 
    replace(datarow,'$$','|') as column2 
    from staging_tbl_single_row 
    ) 
--Insert into SomeTable 
select 
    [1],[2],[3],[4],[5],[6],[7],[8],[9] 
from 
(
    select 
     t.column1, 
     split_values=SUBSTRING(t.column2, t1.N, ISNULL(NULLIF(CHARINDEX('|',t.column2,t1.N),0)-t1.N,8000)), 
     r= row_number() over(partition by column1 order by t1.N) 
    from cte t 
     join 
     (
      select 
       t.column2, 
       1 as N 
      from cte t 
       UNION ALL 
      select 
       t.column2, 
       t1.N + 1 as N 
      from cte t 
       join 
       (
       select 
        top 8000 
         row_number() over(order by (select NULL)) as N 
       from 
        sys.objects s1 
         cross join 
        sys.objects s2 
       ) t1 
      on SUBSTRING(t.column2,t1.N,1) = '|' 
     ) t1 
      on t1.column2=t.column2 
)a 
pivot 
( 
    max(split_values) for r in ([1],[2],[3],[4],[5],[6],[7],[8],[9]) 
    )p 

see working demo

+0

不錯的工作如果我想插入表中選擇你需要在開始寫什麼的結果?插入選擇...? – Tester

0

您可以使用此。

;WITH CTE_1 AS (
    SELECT TXT= TXT +'$$', ID = ROW_NUMBER() OVER(ORDER BY TXT) 
    FROM (VALUES 
      ('BOB$$"DOG"$$"BROWN"$$"9"$$"4"$$"Lat,est"$$$$$$small.'), 
      ('EVA$$"CAT"$$"BLACK"$$"1"$$"4"$$$$"Mouse"$$"Milk"$$small.')) AS X(TXT) 
) 
, CTE_2 AS -- It split text to rows 
(
    SELECT RIGHT(CTE_1.TXT, LEN(CTE_1.TXT) - CHARINDEX('$$',CTE_1.TXT)-1) TXT , SUBSTRING(CTE_1.TXT, 0, CHARINDEX('$$',CTE_1.TXT)) WORD, CHARINDEX('$$',CTE_1.TXT) AS CI, CTE_1.ID, 1 WID 
    FROM CTE_1 
    UNION ALL 
    SELECT RIGHT(CTE_2.TXT, LEN(CTE_2.TXT) - CHARINDEX('$$',CTE_2.TXT)-1) TXT , SUBSTRING(CTE_2.TXT, 0, CHARINDEX('$$',CTE_2.TXT)) WORD, CHARINDEX('$$',CTE_2.TXT) AS CI, CTE_2.ID, WID = WID +1 
    FROM CTE_2 WHERE LEN(CTE_2.TXT) > 0 
) 
SELECT * FROM (SELECT ID, (CASE WHEN WORD='' THEN NULL ELSE WORD END) WORD, WID FROM CTE_2) SRC -- It convert rows to columns by using pivot 
    PIVOT(MAX(WORD) FOR WID IN ([1],[2],[3],[4],[5],[6],[7],[8],[9])) PVT 
OPTION (MAXRECURSION 0) 

結果:

ID     1   2   3   4   5   6   7   8   9 
-------------------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 
1     BOB  "DOG"  "BROWN" "9"  "4"  "Lat,est" NULL  NULL  small. 
2     EVA  "CAT"  "BLACK" "1"  "4"  NULL  "Mouse" "Milk"  small. 
+0

我不知道我是如何將你的東西應用到我的超過100rows – Tester

+0

什麼是你的表和列名稱存儲文本? –

+0

例如,可以在該 '替換CTE_1一部分; WITH CTE_1 AS( \t SELECT \t \t [Column0] TXT,ID = ROW_NUMBER()OVER(ORDER BY [Column0]) \t FROM \t \t [DBO ]。[tablename] )' –

0

的解決方案是不礦,並且示出了一個一般的方法

declare @s varchar(max) ='BOB$$DOG$$BROWN$$9$$4$$Latest$$$$small. 
EVA$$CAT$$BLACK$$1$$4$$$$Mouse$$Mil$$small' 

select 
t.n.value('b[1]', 'varchar(10)'), 
t.n.value('b[2]', 'varchar(10)'), 
t.n.value('b[3]', 'varchar(10)'), 
t.n.value('b[4]', 'varchar(10)'), 
t.n.value('b[5]', 'varchar(10)'), 
t.n.value('b[6]', 'varchar(10)'), 
t.n.value('b[7]', 'varchar(10)'), 
t.n.value('b[8]', 'varchar(10)') 

from 
(select cast(cast('' as xml).query('sql:variable("@s")') as varchar(max))) a(s) cross apply 
(select cast('<a><b>' + replace(replace(a.s, '$$', '</b><b>'), '.', '</b></a><a><b>') + '</b></a>' as xml)) b(x) cross apply 
b.x.nodes('a') t(n); 
0

繼一個簡單的C#例如,其可以容易地轉化爲C#轉換:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace ConsoleApplication10 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string[] MyInput = new string[]{"BOB$$\"DOG\"$$\"BROWN\"$$\"9\"$$\"4\"$$\"Latest\"$$$$ß\"small." 
             , "EVA$$\"CAT\"$$\"BLACK\"$$\"1\"$$\"4\"$$$$\"Mouse\"$$\"Milk\"small."}; 
      int InputIndex = 0; 

      string[] delimiters = new string[]{"$$"}; 

      foreach (string si in MyInput) 
      { 
       string OutCol01 = null, OutCol02 = null, OutCol03 = null, OutCol04 = null, OutCol05 = null 
        , OutCol06 = null, OutCol07 = null, OutCol08 = null, OutCol09 = null, OutCol10 = null; 

       int ColIdx = 0; 

       InputIndex += 1; 

       string[] x = si.Split(delimiters, StringSplitOptions.None); 

       foreach (string s in x) 
       { 
        ColIdx += 1; 

        switch (ColIdx) 
        { 
         case 1: 
          OutCol01 = s; 
          break; 
         case 2: 
          OutCol02 = s; 
          break; 
         case 3: 
          OutCol03 = s; 
          break; 
         case 4: 
          OutCol04 = s; 
          break; 
         case 5: 
          OutCol05 = s; 
          break; 
         case 6: 
          OutCol06 = s; 
          break; 
         case 7: 
          OutCol07 = s; 
          break; 
         case 8: 
          OutCol08 = s; 
          break; 
         case 9: 
          OutCol09 = s; 
          break; 
         case 10: 
          OutCol10 = s; 
          break; 
         default: 
          break; 
        } 
       } 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol01); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol02); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol03); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol04); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol05); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol06); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol07); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol08); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol09); 
       Console.WriteLine(InputIndex.ToString() + " - " + OutCol10); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 
0

您也可以嘗試,如果你有fix 9 Column Data

SELECT CASE 
      WHEN Column1 = '' 
      THEN NULL 
      ELSE Column1 
     END Column1, 
     CASE 
      WHEN Column2 = '' 
      THEN NULL 
      ELSE Column2 
     END Column2, 
     CASE 
      WHEN Column3 = '' 
      THEN NULL 
      ELSE Column3 
     END Column3, 
     CASE 
      WHEN Column4 = '' 
      THEN NULL 
      ELSE Column4 
     END Column4, 
     CASE 
      WHEN Column5 = '' 
      THEN NULL 
      ELSE Column5 
     END Column5, 
     CASE 
      WHEN Column6 = '' 
      THEN NULL 
      ELSE Column6 
     END Column6, 
     CASE 
      WHEN Column7 = '' 
      THEN NULL 
      ELSE Column7 
     END Column7, 
     CASE 
      WHEN Column8 = '' 
      THEN NULL 
      ELSE Column8 
     END Column8, 
     CASE 
      WHEN Column9 = '' 
      THEN NULL 
      ELSE Column9 
     END Column9 
FROM 
(
    SELECT DISTINCT 
      Split.a.value('/M[1]', 'NVARCHAR(MAX)') Column1, 
      Split.a.value('/M[2]', 'NVARCHAR(MAX)') Column2, 
      Split.a.value('/M[3]', 'NVARCHAR(MAX)') Column3, 
      Split.a.value('/M[4]', 'NVARCHAR(MAX)') Column4, 
      Split.a.value('/M[5]', 'NVARCHAR(MAX)') Column5, 
      Split.a.value('/M[6]', 'NVARCHAR(MAX)') Column6, 
      Split.a.value('/M[7]', 'NVARCHAR(MAX)') Column7, 
      Split.a.value('/M[8]', 'NVARCHAR(MAX)') Column8, 
      Split.a.value('/M[9]', 'NVARCHAR(MAX)') Column9 
    FROM 
    (
     SELECT CAST('<M>'+REPLACE(<Column>, '$$', '</M><M>')+'</M>' AS XML) AS String 
     FROM <table_name> 
    ) A 
    CROSS APPLY String.nodes('/M') Split(a) 
) A; 

所需的輸出:

Column1 Column2 Column3 Column4 Column5 Column6  Column7 Column8  Column9 
BOB  "DOG"  "BROWN" "9"  "4" "Lat,est"  NULL  NULL  small. 
EVA  "CAT"  "BLACK" "1"  "4"  NULL  "Mouse"  "Milk"  small. 
+0

Msg 9421,Level 16,State 1,Line 1 XML解析:第1行,字符880,非法名稱字符 – Tester

+0

@Tester sh ur查詢嘗試。 –

0

使用,儘管你已經接受了不同的解決方案,我想

查詢來說明如何解決這個SSIS方式與絕對無需編碼:

1)如果不存在,請添加數據流元素到您的包控制流。

2)轉到數據流並添加平面文件源元素。

3)單擊以編輯平面文件源。

  • 連接管理器窗格中,選中複選框「中的數據從源保留空值作爲空值流」

  • 點擊新建...按鈕創建一個新的平面文件連接。

4)平面文件連接管理器編輯,單擊瀏覽...打開源文件。

  • 選擇所需的代碼頁/編碼

  • 離開預先選擇的默認值格式文本限定符標題行定界符標題行跳過

  • 取消選中「第一個數據行中的列名」(unlele SS比你的例子外,你的真實文件包含一個標題行)

5)切換到窗格和改變列分隔符$$(只要輸入 - 列出的值是隻是建議作爲選擇的最常用的)

  • 點擊刷新按鈕查看列得到認可,你期望的方式。

6)切換到高級窗格。

  • 選擇左側列表框的每一個欄和編輯名稱屬性設置爲一個有意義的值

  • 修改OutputColumnWidth值需要的地方。

  • 選擇左側列表框和大衆編輯TextQualifiedFalse所有列...這將確保根據需要你周圍的報價將被保留。

  • 切換到預覽窗格檢查並關閉與OK平面文件連接編輯器。

7)關閉平面文件源編輯與OK

8)添加所需的目標(OLE DB)和連接您的平面文件源