2016-12-01 4 views
0

Ex.T-SQL: отдельная строка в нескольких столбцах

Column 1: 
| word1 word2 word3 word4 | 

в

Col 1: Col 2: Col 3: Col 4: 
| word1 | word2 | word3 | word | 

Можно ли отделить различные слова или фразы из строки в несколько столбцов? Все слова и фразы в строках обычно разделяются двойными пробелами, больше ничего. Есть ли предопределенная функция, которую я могу использовать уже доступную с SQL Server, например CAST или INTERSECT, или мне нужно написать свой собственный?

ответ

0

здесь является динамическая версия SQL. от Иоанна в случае, если вы не знаете максимальное количество слов. Ключевыми методами для достижения того, что вы хотите, будет разделение строки и сводной (или условной агрегации). Потому что вы как бы делаете оба сразу, метод Джона - хороший ярлык.

IF OBJECT_ID('tempdb..#TblName') IS NOT NULL 
    BEGIN 
     DROP TABLE #TblName 
    END 

CREATE TABLE #TblName (
    ID INT IDENTITY(1,1) 
    ,String VARCHAR(500) 
) 

INSERT INTO #TblName VALUES ('word1 word2 word3 word4'),('abcd efgh ijkl') 

DECLARE @NumWords INT 

SELECT @NumWords = ISNULL(MAX((LEN(String) - LEN(REPLACE(String,' ','')))/2 + 1), 0) 
FROM 
    #TblName 

DECLARE @i INT = 1 
DECLARE @SQL NVARCHAR(MAX) 

SET @SQL = ' 
SELECT 
    t.Id 
    ,t.String 
    ,c.* 
FROM 
    #TblName t 
    CROSS APPLY (
     SELECT 

      ' 
WHILE @i <= @NumWords 
BEGIN 
    SET @SQL = @SQL 
      + IIF(@i > 1,', ','') 
      + 'Column' + CAST(@i AS NVARCHAR(MAX)) + '1 = x.value (''/x[' + CAST(@I AS NVARCHAR(MAX)) + ']'',''varchar(max)'')' 

    SET @i = @i + 1 
END 

SET @SQL = @SQL + ' 
     FROM 
      (SELECT CAST(''<x>'' + REPLACE(String,'' '',''</x><x>'') + ''</x>'' as XML) x) a 
    ) c' 


EXECUTE (@SQL) 
+0

Максимальное количество столбцов - 4, поэтому всегда будет 4 столбца, но если строка содержит только 3 слова, то для этой строки будут использоваться только 3 новых столбца. Ваша функция очень хорошая, но могу ли я ввести имя столбца в качестве вставленного значения, или мне нужно записать каждое слово один за другим? Каждая строка из исходного столбца имеет различный набор слов для каждой строки, а иногда слова меняются каждый день или неделю, поэтому я не могу переписывать все слова каждый раз, так что есть способ заставить вашу функцию автоматически извлекать слова из оригинальная колонка? –

+0

Если будет максимум 4 столбца, я бы использовал ответ Джона, поскольку это было бы излишним. Я не следую тому, что вы имеете в виду, если бы вам пришлось записывать каждое слово, так как работы будут автоматически разбиты на вас. Вы можете быть отброшены, потому что я назвал столбец word1, word2 и т. Д. Так что я только что обновил и изменил это на Column, надеюсь, что это устранит путаницу. – Matt

1

С помощью CROSS APPLY и некоторых XML. Легко для того чтобы расширить и/или контракт

Declare @YourTable table (id int,Column1 varchar(max)) 
Insert Into @YourTable values 
(1,'word1 word2 word3 word4'), 
(2,'some other words') 

Select A.ID 
     ,B.* 
From @YourTable A 
Cross Apply (
     Select Pos1 = xDim.value('/x[1]','varchar(max)') 
       ,Pos2 = xDim.value('/x[2]','varchar(max)') 
       ,Pos3 = xDim.value('/x[3]','varchar(max)') 
       ,Pos4 = xDim.value('/x[4]','varchar(max)') 
       ,Pos5 = xDim.value('/x[5]','varchar(max)') 
       ,Pos6 = xDim.value('/x[6]','varchar(max)') 
       ,Pos7 = xDim.value('/x[7]','varchar(max)') 
       ,Pos8 = xDim.value('/x[8]','varchar(max)') 
       ,Pos9 = xDim.value('/x[9]','varchar(max)') 
     From (Select Cast('<x>' + Replace(A.Column1,' ','</x><x>')+'</x>' as XML) as xDim) A 
     ) B 

Возвращает

enter image description here

+0

Это очень хорошо, но проблема в том, что я не определяю список слов; исходный столбец имеет несколько строк, каждый с другой строкой, и я не могу записать каждую строчку один за другим, функция должна делать это автоматически, тем более, что строки могут отличаться от каждой учетной записи, и они меняются каждый день. Есть ли способ сделать вашу функцию более динамичной, поэтому она может работать с несколькими переменными? –

+0

@ K.Ventura (at) YourTable - это демонстративная переменная таблицы. Замените (at) YourTable своим фактическим именем таблицы и A.Column1 с вашим фактическим именем поля, и он запустится. Когда вы говорите динамический, что именно вы ищете, –

0

Если количество слов не является фиксированной numbr, вы можете использовать динамический сценарий, эпидермальный образец:

IF OBJECT_ID('tempdb..#tb') IS NOT NULL DROP TABLE #tb 
CREATE TABLE #tb (id int,Column1 varchar(max)) 
insert Into #tb values 
(1,'word1 word2 word3 word'), 
(2,'w1 w2 w3 w4 w5 w6') 

DECLARE @Cols NVARCHAR(max),@sql nvarchar(MAX) 
DECLARE @MaxWordCount INT 
SELECT @MaxWordCount=MAX(LEN(t.Column1)-len(replace(t.Column1,' ',''))+1) from #tb as t 
    SELECT @Cols=ISNULL(@Cols+',','')+'[Col '+LTRIM(sv.number)+']' FROM master.dbo.spt_values as sv WHERE sv.Type='P' and sv.number BETWEEN 1 AND @MaxWordCount 

PRINT @Cols 
SET @sql='SELECT * from (
      SELECT t.*, w.* FROM #tb AS t 
      CROSS APPLY (VALUES (convert(XML, ''<n>'' + replace(t.Column1, '' '', ''</n><n>'') + ''</n>''))) x(c) 
      CROSS APPLY (SELECT ''Col '' + ltrim(row_number()OVER (ORDER BY getdate())) AS col 
           ,s.b.value(''.'', ''varchar(200)'') AS wd 
          FROM x.c.nodes(''n'') s(b)) w 
     ) a PIVOT (max(wd) for col in ('[email protected]+')) p' 
PRINT @sql 
EXEC(@sql) 
IF OBJECT_ID('tempdb..#tb') IS NOT NULL DROP TABLE #tb 
 
id Column1 Col 1 Col 2 Col 3 Col 4 Col 5 Col 6 
2 w1 w2 w3 w4 w5 w6 w1 w2 w3 w4 w5 w6 
1 word1 word2 word3 word word1 word2 word3 word NULL NULL 
0

Как насчет этого?

Create Table AllData (Column0 varchar(500)) 
Insert Into AllData Values ('word1 word2 word3 word4') 
Select parsename(replace(replace(replace([Column0],' ',' '),' ',' '),' ','.'), 4) [Col1], 
parsename(replace(replace(replace([Column0],' ',' '),' ',' '),' ','.'), 3) [Col2], 
parsename(replace(replace(replace([Column0],' ',' '),' ',' '),' ','.'), 2) [Col3], 
parsename(replace(replace(replace([Column0],' ',' '),' ',' '),' ','.'), 1) [Col4] 

from AllData 
Смежные вопросы