将VARCHAR列拆分为多个列

时间:2019-06-03 22:17:39

标签: sql-server sql-server-2014

我正在努力将列中的数据分成多列。 我有客户姓名数据,数据需要清理,因为可能有重复项,我还需要为将来的数据建立新的标准。 我已经能够成功拆分字符串中的前两个单词,但无法拆分更多数据。

我仅具有读取权限。所以我无法创建任何功能。

例如:

客户名称:伊利诺伊理工学院

我的查询只会在一个列中获取“伊利诺伊州”,而在另一列中获取“技术研究所”。考虑将定界符视为“空格”,我希望将每个单词分成单独的列。我不确定如何识别第二个空间和更多空间。

我也尝试过使用'parsename'函数,但是我认为这将在清除数据方面增加难度。

select name, 
left (name, CHARINDEX(' ', name)) as f,
substring(name, CHARINDEX(' ', name)+1, len(name)) as s
from customer

2 个答案:

答案 0 :(得分:0)

一旦检索到数据,您就不会提及您打算如何处理它们。由于您仅具有读取权限,因此无法将其存储在表中。您可能没有想到的事情是创建一个本地数据库,在该数据库中您具有写权限并在那里进行工作。最简单的方法是获取数据库的副本,但您也可以使用完全限定的名称访问只读数据库。

关于您的字符串拆分需求,我可以为您介绍一种拆分由杰夫·摩登先生创建的字符串的好方法。您可以在此处找到讨论它的文章以及代码链接:

Tally OH! An Improved SQL 8K “CSV Splitter” Function

尽管这是一本非常有帮助的读物,但由于它大部分是关于性能测试的,所以您可能希望跳过其中的大部分内容,直接编写代码,但请尝试挑选讨论功能性的内容并阅读该书。因为该代码最多会将非常规代码视为非常规代码。

代码创建了一个函数,但是由于您没有执行此操作的权限,因此必须从函数中删除肉并直接使用它。

我将为您提供一些入门方法的概述。

方法的核心是理货单。如果您不熟悉该术语(也称为Numbers表),则它基本上是一个表,其中每一行都包含一个整数,并且该行基本上是某个范围内的所有整数的集合,通常非常大。那么Tally Table如何帮助拆分字符串?通过将计数表连接到包含要拆分的字符串的表,并使用where子句通过查看由计数表编号索引的1个字符的子字符串来识别定界符,就可以实现魔术。然后,SQL Server基于集合的自然操作一次性搜索所有定界符,然后您的选择列表提取定界符括起来的子字符串。这真的非常聪明而且非常快捷。

进入代码后,该函数的第一部分可能看起来很奇怪(因为确实如此),但是由于您只有读取权限,因此这是必需的。它基本上是使用SQL Server的通用表表达式(CTE)功能,使用一些您并不需要真正理解的丑陋逻辑来动态构建内部理货表(但是如果您要进行深入研究,即使它是聪明的,也很聪明)。丑陋)。由于该表仅在查询本地,因此不会违反您的只读权限。

它还使用CTE来表示分隔的子字符串的起始索引和长度,因此最终查询非常简单,生成的行带有行号,后跟原始数据中的字符串。

我希望这可以帮助您完成任务-它确实是您工具包中的一个不错的工具。

编辑:我刚刚意识到,您希望输出位于单独的列而不是行中。这要困难得多,因为要拆分的每个列可能会产生不同数量的字符串,而且您的列将需要名称。如果您已经知道列名并知道输出字符串的数量,这将比较容易,但仍然很棘手。可以对拆分器中的行数据进行调整,以提供数据所在行的标识符,并且如果需要,行号可以帮助创建任意的列名,但是最大的问题是,只有读取权限才能找到处理对象步伐相当棘手-甚至可以进一步使用CTE,但是除非要求非常简单,否则您的代码可能会变得相当混乱。

答案 1 :(得分:0)

编辑:这仅适用于SQL Server 2016及更高版本。 OP具有SQL Server 2014。

实际上并没有的方法,但这是一种可能对您有用的方法,是从示例here修改而来的:

create table #customer (id int, name nvarchar(max))

insert into #customer
values  (1, 'Illinois Institute of Technology'), 
        (2, 'The City University of New York'), 
        (3, 'University of the District of Columbia'), 
        (4, 'Santa Fe University of Art and Design')

;   
with c as(
select id, name
      ,value
      ,row_number() over(partition by id order by (select null)) as rn
from #customer
cross apply string_split(name, ' ') as bk
)
select id, name
      ,[1]
      ,[2]
      ,[3]
      ,[4]
      ,[5]
      ,[6]
from c
pivot(
    max(value)
    for rn in([1],[2],[3],[4],[5],[6])  
) as pvt

drop table #customer

注意几件事:

  1. 您必须在输出中显式声明列。您可以创建一些过于复杂的动态SQL,该SQL会根据需要生成尽可能多的列名,但是这会使解决问题和进行修改变得更加困难,并且您可能不会获得相同的查询优化。
  2. 由于(1),如果太多单词无法容纳已定义的列数,您最终将丢掉单词。请参阅最后一个示例,id = 4。
  3. 提防其他可能无法使您的单词保持顺序或跳过重复单词的方法,例如。示例id = 3中为“ of”。
相关问题