SQL Server将值拆分为列

SQL Server将值拆分为列,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,我的字符串由$$字符分隔,如下所示: BOB$$"DOG"$$"BROWN"$$"9"$$"4"$$"Latest"$$$$$$"small. EVA$$"CAT"$$"BLACK"$$"1"$$"4"$$$$"Mouse"$$"Milk"$$small. 我想获得使用后的功能:更新/插入select/SSIS映射 如下表所示: Column1 Column2 Column3 Column4 Column5 Column6 Column7 Column8

我的字符串由$$字符分隔,如下所示:

BOB$$"DOG"$$"BROWN"$$"9"$$"4"$$"Latest"$$$$$$"small.
EVA$$"CAT"$$"BLACK"$$"1"$$"4"$$$$"Mouse"$$"Milk"$$small. 
我想获得使用后的功能:更新/插入select/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. 
我可以使用函数Update/Insert-into-select生成9行以获得结果吗? 我可以创建两个表;第一个表包含单列,第二个表包含9列或10列

我需要100多行的通用解决方案。以上两行只是示例

我想继续使用这种类型的代码:

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

FROM    [dbo].[tablename]
你可以用这个

;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.

解决方案不是我的,而是一种通用方法

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

下面是一个简单的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();
        }
    }
}

如果您有修复9列数据,也可以尝试:


你在正确的轨道上。在使用SSI导入平面文件时,我们通常将所有内容作为varchar数据类型列表(称为暂存表)导入,然后检查列值的数据类型一致性。 这使我们能够导入所有内容,而不会丢失数据,并为清理数据提供了机会

方法1:对于您的情况,可以在SSIS数据流任务源中使用$$作为列分隔符。 SSIS不关心标题列的顺序或名称。标题名称中可以有任何内容,如第1列、第2列等。 在这种方法中,您可以将数据从文件导入到9列表中。如果某些行中的列较少/较多,此方法将失败

方法2:将所有内容作为单个列导入varchar staging table1。 从这里您可以拆分所有列并插入到另一个9列的varchar staging table 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

尽管您已经接受了另一种解决方案,但我想展示如何以SSIS方式解决此问题,而无需任何编码:

1如果尚未存在,请将数据流元素添加到包控制流中

2转到数据流并添加平面文件源元素

3单击以编辑平面文件源

在“连接管理器”窗格上,将源中的保留空值复选框标记为数据流中的空值

单击新的。。。按钮创建新的平面文件连接

4在平面文件连接管理器编辑器上,单击浏览。。。打开源文件

选择所需的代码页/编码

保留要跳过的格式、文本限定符、标题行分隔符和标题行的预选默认值

取消选中第一个数据行中的列名,除非您的示例之外,您的真实文件包含标题行

5切换到Columns窗格,并将Column delimiter更改为$$just type in-列出的值只是作为最常用值的选择

单击“刷新”按钮,可以看到您的列按预期方式被识别。 6切换到高级窗格

选中左侧列表框中的每一列,并将Name属性编辑为有意义的值

根据需要修改OutputColumnWidth的值

选择左侧列表框中的所有列并批量编辑文本限定为False。。。这将确保您周围的报价按需要保留

切换到预览窗格以检查平面文件连接编辑器,并用“确定”关闭该编辑器

7使用“确定”关闭平面文件源编辑器


8添加所需的目标OLE DB并连接平面文件源

您的数据是平面文件源吗?您真的打算将引号作为数据保存吗?@filburt Yes是平面文件CSV,但我每天都使用100多个SSI,但我在将1250语言转换为1252方面有问题Visual basic studio在SQL server方面有问题。。。对我来说很容易我认为这是一种方法如果您使用SSI,配置平面文件数据源应该很容易:您可以设置所需的代码页,指定列分隔符$$,并保留引号。我不认为需要任何手写代码。如果您还没有尝试过,我建议您在SSIS中创建一个数据流,并探索平面文件数据源提供的选项。@Filburt我在SSIS/Bulk Insert HDL.fmt文件中尝试了3天的拆分,但效果不好。所有建议手工拆分的答案都过于复杂,使维护或添加新列变得更加困难。我刚刚配置了一个平面文件源,在5分钟内生成所需的管道数据。我强烈推荐@DhruvJoshi的方法1。我不知道如何在我的100多行上应用你的东西存储文本的表和列名是什么?例如,你可以用这个替换CTE_1部分;使用CTE_1作为SELECT[Column0]TXT,ID=从[dbo].[tablename]通过[Column0]对[Column0]进行排序,使用选项maxrecursion 0,需要将相同的值从第10列移动到第13列,并且需要将第11列到第12列的一些相同值从第10列移动到第13列和som
从第11列到第12列我不明白,你能举个例子吗?Msg 9421,16级,状态1,第1行XML解析:第1行,字符880,非法名称character@Testershw ur查询尝试。如果我想在表中插入您的结果,请选择我需要在开始时写入的内容?插入到选择。。。?
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. 
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