Как разделить имена на первое / среднее / последнее, если есть люди, которые набрали последнее / первое / среднее?Порядок известный - PullRequest
1 голос
/ 16 июня 2019

Я пытаюсь разбить имена на первое, среднее, последнее в соответствии с указанным порядком. Я не знаю, как это сделать, и любая помощь будет принята с благодарностью. Я использую SQL Server 2008 для работы.

Я приложил пример набора данных и идеальный набор данных, который я хотел бы создать.

ID  ORDER                   NAME
1   first, middle, last     Bruce, Batman, Wayne
2   middle, last, first     Superman, Kent, Clark
3   last, first, middle     Prince, Diana, Wonderwoman

INTO:

ID  ORDER                   NAME
1   first                   Bruce
1   middle                  Batman
1   last                    Wayne
2   middle                  Superman
2   last                    Kent
2   first                   Clark
3   last                    Prince
3   first                   Diana
3   middle                  Wonderwoman

Ответы [ 3 ]

0 голосов
/ 16 июня 2019

С помощью функции синтаксического анализа / разделения, которая возвращает последовательность, это становится небольшим вопросом, используя CROSS APPLY

Пример

Select A.ID 
      ,B.*
 From  YourTable A
 Cross Apply (
                Select [Order] = B1.RetVal
                      ,[Name]  = B2.RetVal
                 From  [dbo].[tvf-Str-Parse]([ORDER],',') B1
                 Join  [dbo].[tvf-Str-Parse]([NAME] ,',') B2 on B1.RetSeq=B2.RetSeq
             ) B

Возвращает

ID  Order   Name
1   first   Bruce
1   middle  Batman
1   last    Wayne
2   middle  Superman
2   last    Kent
2   first   Clark
3   last    Prince
3   first   Diana
3   middle  Wonderwoman

Функция, если она заинтересована

CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = row_number() over (order by 1/0)
          ,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From  ( values (cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.'))) as A(x)
    Cross Apply x.nodes('x') AS B(i)
);
0 голосов
/ 16 июня 2019

Мне показалось, что другие ответы немного сложны для понимания - они, конечно, изящные уловки, но я думаю, что любой, кто придет поддержать их, может быть похож на «аааааа?». Здесь я работаю с индексами запятых (первый индекс строки запятой идет в o1 / n1, вторая запятая идет в o2 / n2) в первом cte, вырезать строку вверх (подстрока между 1 и первой запятой, подстрока между первым и вторая запятая, подстрока после третьей запятой) во втором cte, а затем с помощью пары объединений превратить результаты из 7 столбцов в 3

WITH idxs AS
(
SELECT 
  id,
  order,
  name,
  CHARINDEX(',', [order]) as o1,
  CHARINDEX(',', [order], CHARINDEX(',', [order]) + 1) as o2,
  CHARINDEX(',', name) as n1,
  CHARINDEX(',', name, CHARINDEX(',', name) + 1) as n2
FROM
  t
),
cuts as (
SELECT
  id,
  SUBSTRING([order], 1, o1-1) as ord1,
  SUBSTRING([order], o1+1, o2-o1-1) as ord2,
  SUBSTRING([order], o2+1, 4000) as ord3,
  SUBSTRING(name, 1, n1-1) as nam1,
  SUBSTRING(name, n1+1, n2-n1-1) as nam2,
  SUBSTRING(name, n2+1, 4000) as nam3
FROM
  idxs
)

SELECT id, ord1 as [order], nam1 as name FROM cuts
UNION ALL
SELECT id, ord2, nam2 FROM cuts
UNION ALL
SELECT id, ord3, nam3 FROM cuts

Обратите внимание, что если в ваших данных иногда есть пробелы, а иногда нет, вы получите выгоду от использования LTRIM / RTRIM в выходных данных

если пробелы всегда присутствуют после запятой, вы также можете настроить индексы подстрок, чтобы вырезать пробелы (любой начальный индекс, равный x + 1, будет равен x + 2, а длина, следовательно, должна быть равна -2)

0 голосов
/ 16 июня 2019

SQL Server не имеет очень хороших функций обработки строк.Вы можете сделать это с помощью рекурсивного CTE, однако:

with cte as (
      select id,
             convert(varchar(max), left(ord, charindex(',', ord) - 1)) as ord,
             convert(varchar(max), left(name, charindex(',', name) - 1)) as name,
             convert(varchar(max), stuff(ord, 1, charindex(',', ord) + 1, '')) as ord_rest,
             convert(varchar(max), stuff(name, 1, charindex(',', name) + 1, '')) as name_rest,
             1 as lev
      from t
      union all
      select id,
             convert(varchar(max), left(ord_rest, charindex(',', ord_rest + ',') - 1)) as ord,
             convert(varchar(max), left(name_rest, charindex(',', name_rest + ',') - 1)) as name,
             convert(varchar(max), stuff(ord_rest, 1, charindex(',', ord_rest + ',') + 1, '')) as ord_rest,
             convert(varchar(max), stuff(name_rest, 1, charindex(',', name_rest + ',') + 1, '')) as name_rest,
             lev + 1
      from cte
      where ord_rest <> '' and lev < 10
     )
select id, ord, name
from cte
order by id, lev

Здесь - это db <> скрипка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...