SQL: перекрестное применение для разделения имен на first, last и MI - PullRequest
0 голосов
/ 05 апреля 2019

У меня есть таблица с такими именами пользователей.

Name
-----
Smith-Bay, Michael R.
Abbott, David Jr.
Actor, Cody
Agular, Stephen V.

Мне нужно, чтобы имя выглядело так:

Last         First    MI
-------------------------
Smith-Bay    Michael  R
Abbott       David    Jr
Actor        Cody
Agular       Stephen  V 

У меня есть следующий SQL, который разбивает имя напервый и последний:

select vl.lastname, vf.firstname
from users as t cross apply
(values (left(t.name, charindex(', ', t.name)), stuff(t.name, 1, 
charindex(', ', t.name) + 1, ''))) vl(lastname, rest) 
cross apply 
(values (left(vl.rest, charindex(' ', vl.rest + ' ')))) vf(firstname)
order by  vl.lastname

Как применить еще один крестик, чтобы извлечь практически все после имени без периода в конце?

1 Ответ

1 голос
/ 05 апреля 2019

Мне приходилось делать это много раз, так как я работаю с ETL на регулярной основе, и мне нужно либо извлекать элементы из строк, либо из-за плохого хранения данных, либо просто из-за необходимости извлекать данные из отчетов.Данные не всегда красиво упакованы в отдельные столбцы, и я обнаруживаю, что анализирую данные по разным причинам.Надеемся, что данные, которые вы анализируете, согласуются.Непоследовательные данные либо делают это намного более трудным, либо невозможным.Если вы можете полагаться на то, что ваши имена точно соответствуют формату, который вы предложили, мой метод, приведенный ниже, будет работать отлично.Я использовал это во многих случаях.

Метод, приведенный ниже, я использовал на разных языках.Я сделал это в MS ACCESS, Microsoft SSMS и C #.Мой пример выходит за пределы Oracle.

Основная идея:

Find the character positions, которые разделяют строки First_Name, Last_Name и Middle_Initial.

Extract Strings into New Columns используя полученные позиции символов.

enter image description here

Код ниже:

WITH character_pos AS
(
/* First we need the character positions for spaces, commas and the period for the middle initial */
SELECT name
  /* Find 1st Space in the name so we can extract the first name from the string */
  , instr(name, ', ') AS comma_1st_space_pos
  /* Find 2nd Space in the name so we can extract the last name from the string */
  , instr(name, ' ', 1, 2) AS comma_2nd_space_pos
  /* Get the Length of the last name so we know how many characters the substr function should extract */
  , instr(name, ' ', 1, 2) - (instr(name, ', ') + 2) AS last_name_length
  /* Find period in the name so we can extract the Middle Initial should it exist */
  , instr(name, '.')  AS period_pos
  , (instr(name, '.') - 1) - instr(name, ' ', 1, 2) AS middle_initial_length

FROM parse_name
) /* END character_pos CTE */

SELECT name  
  , substr(name, 0, comma_1st_space_pos -1) AS last_name

  , CASE WHEN  period_pos = 0 THEN substr(name, comma_1st_space_pos + 2)
    ELSE substr(name, comma_1st_space_pos + 2, last_name_length) 
    END AS first_name

  , substr(name, comma_2nd_space_pos + 1, middle_initial_length) AS middle_initial

  , comma_1st_space_pos, comma_2nd_space_pos, last_name_length
  , period_pos, middle_initial_length
FROM character_pos
;

Я использовалCTE просто для организации позиций символов вне фактического извлечения, однако все это может быть сделано в одном единственном операторе SQL.

По сути, это доказывает, что вам не нужно ничего дополнительного, кроме простых функций разбора строк.Все, что вам нужно, это Instring и Substring, которые обычно доступны на любом языке.Нет хранимых процедур, никакой временной таблицы и никакого дополнительного внешнего кода не требуется.Если нет других факторов, выходящих за рамки первоначального вопроса, которые заставляют использовать что-либо кроме SQL.

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