Инструкция TSQL для перемещения суффикса имени (Jr, Sr, IV и т. Д.) В другое поле - PullRequest
0 голосов
/ 14 сентября 2010

Я хотел бы иметь оператор TSQL для перемещения суффикса имени (Jr, Sr., IV и т. Д.) В другое поле.

Я вижу суффиксы JR SR I II III IV V

Вот пример данных

LastName
BRUNNING, II
BURCH II
BUSS, JR.
CANI III
CHRISTIAN,SR
COLVIN Jr
COWHERD,JR.

Я бы хотел, чтобы суффикс был перемещен из поля LastName в другое поле с именем Suffix.

LastName   Suffix  
BRUNNING   II
BURCH      I     
BUSS       JR
CANI       III
CHRISTIAN  SR
COLVIN     JR
COWHERD    JR

Я использую SQL Server2005 и может использовать SQL # функции.
Любая помощь будет высоко оценена.

Ответы [ 5 ]

1 голос
/ 20 января 2011

Если CLR не вариант, то, что предложил Питер, замечательно.Однако, поскольку вы сказали, что у вас есть SQL #, вы можете сделать это более простым и функциональным способом, используя функцию RegEx_MatchSimple в SQL #.Я объясню, используя пример Питера в качестве отправной точки.

Мы можем настроить тест, используя почти тот же SQL, который использовал Питер, но в этом случае я создам таблицу суффиксов как реальную (не временную) таблицутак что я могу сослаться на это в одном из примеров TVF ниже.Возможно, вы захотите сохранить их в таблице, а не передавать в качестве параметра, но я покажу оба стиля.Я также добавил два имени в таблицу #Names, чтобы показать, как использование RegEx может помочь зафиксировать изменения в данных (дополнительные пробелы и / или запятые):

USE [tempdb]
GO
IF OBJECT_ID('tempdb..#Names') IS NOT NULL DROP TABLE #Names
IF OBJECT_ID('tempdb.dbo.Suffixes') IS NOT NULL DROP TABLE dbo.Suffixes
CREATE TABLE #Names (LastName VARCHAR(32))
CREATE TABLE dbo.Suffixes (Suffix VARCHAR(32))
GO

INSERT #Names VALUES ('BRUNNING, II'  )
INSERT #Names VALUES ('BURCH II'      )
INSERT #Names VALUES ('BUSS, JR.'     )
INSERT #Names VALUES ('CANI III'      )
INSERT #Names VALUES ('CHRISTIAN,SR'  )
INSERT #Names VALUES ('COLVIN Jr'     )
INSERT #Names VALUES ('COWHERD,JR.'   )
INSERT #Names VALUES ('BILLY BOB'     )
INSERT #Names VALUES ('JOHNNY'        )
INSERT #Names VALUES ('BRUNNING, II ' )
INSERT #Names VALUES ('SMITH ,, SR. ' )

INSERT dbo.Suffixes VALUES ('II' )
INSERT dbo.Suffixes VALUES ('III')
INSERT dbo.Suffixes VALUES ('JR' )
INSERT dbo.Suffixes VALUES ('SR' )

Первое, что нужно показать, - это простой примерэто работает с вышеуказанными данными.В этом случае я использую CTE, чтобы сгенерировать список совпадений с именами, а затем отфильтровать строки, которые ничего не совпадают.Я заключил поле [FullMatch] в двоеточия, чтобы было легче увидеть захваченные начальные и конечные пробелы:

;WITH cte AS (
    SELECT  names.LastName,
            [SQL#].[SQL#].RegEx_MatchSimple(names.LastName, '(([ ]*,+[ ]*)|([ ]+))' + suff.Suffix + '[.]*[ ]*$', 1, 'IgnoreCase') AS [FullMatch],
            suff.suffix
    FROM    #Names names
    CROSS JOIN tempdb.dbo.Suffixes suff
)
SELECT  cte.LastName, ':' + cte.FullMatch + ':' AS [FullMatch], REPLACE(cte.LastName, cte.FullMatch, '') AS [Replacement], cte.Suffix
FROM    cte
WHERE   cte.FullMatch <> ''

Вы можете перенести эту теорию в прямой оператор UPDATE:

;WITH cte AS (
    SELECT  names.LastName,
            [SQL#].[SQL#].RegEx_MatchSimple(names.LastName, '(([ ]*,+[ ]*)|([ ]+))' + suff.Suffix + '[.]*[ ]*$', 1, 'IgnoreCase') AS [FullMatch],
            suff.Suffix
    FROM    MyTable names
    CROSS JOIN NameSuffixes suff
)
UPDATE  mt
SET     mt.LastName = REPLACE(cte.LastName, cte.FullMatch, ''),
        mt.NameSuffix = cte.Suffix
FROM    MyTable mt
INNER JOIN  cte
        ON  cte.LastName = mt.LastName
WHERE   cte.FullMatch <> ''

Вы запросили это как функцию, которая выглядит следующим образом:

CREATE FUNCTION dbo.ParseNameAndSuffix (@Name VARCHAR(64))
RETURNS TABLE AS RETURN
(
    WITH cte AS (
        SELECT  @Name AS [LastName],
                [SQL#].[SQL#].RegEx_MatchSimple(@Name, '(([ ]*,+[ ]*)|([ ]+))' + suff.Suffix + '[.]*[ ]*$', 1, 'IgnoreCase') AS [FullMatch],
                suff.Suffix
        FROM    tempdb.dbo.Suffixes suff
    )
    SELECT  cte.LastName, cte.FullMatch, REPLACE(cte.LastName, cte.FullMatch, '') AS [Replacement], cte.Suffix
    FROM    cte
    WHERE   cte.FullMatch <> ''
)
GO

И может использоваться следующим образом:

SELECT  *   
FROM    #Names a
CROSS APPLY dbo.ParseNameAndSuffix(a.LastName) b

-- or --

UPDATE  mt
SET     mt.LastName = REPLACE(parse.LastName, parse.Found, ''),
        mt.NameSuffix = parse.Suffix
FROM    MyTable mt
CROSS APPLY dbo.ParseNameAndSuffix(mt.LastName) parse

Чтобы более точно соответствовать примеру, приведенномуПитер, который передал суффиксы в качестве параметра, что можно сделать следующим образом, используя функцию String_Split в SQL #:

CREATE FUNCTION dbo.ParseNameAndSuffix2 (@Name VARCHAR(64), @Suffixes VARCHAR(MAX))
RETURNS TABLE AS RETURN
(
    WITH cte AS (
        SELECT  @Name AS [LastName],
                [SQL#].[SQL#].RegEx_MatchSimple(@Name, '(([ ]*,+[ ]*)|([ ]+))' + suff.Val + '[.]*[ ]*$', 1, 'IgnoreCase') AS [FullMatch],
                suff.Val AS [Suffix]
        FROM    [SQL#].[SQL#].String_Split(@Suffixes, ';', 2) suff
    )
    SELECT  cte.LastName, cte.FullMatch, REPLACE(cte.LastName, cte.FullMatch, '') AS [Replacement], cte.Suffix
    FROM    cte
    WHERE   cte.FullMatch <> ''
)
GO

, которую затем можно использовать следующим образом:

SELECT * FROM #Names a
CROSS APPLY dbo.ParseNameAndSuffix2(a.LastName, 'II;III;JR;SR') b

-- or --

UPDATE  mt
SET     mt.LastName = REPLACE(parse.LastName, parse.Found, ''),
        mt.NameSuffix = parse.Suffix
FROM    MyTable mt
CROSS APPLY dbo.ParseNameAndSuffix2(mt.LastName, 'II;III;JR;SR') parse
1 голос
/ 15 сентября 2010

Вы, вероятно, можете добиться большего успеха, чем это, используя функции SQL #, но в прямом T-SQL, здесь вы идете.

Основная идея здесь состоит в том, чтобы проанализировать последний сегмент / токен в имени, используя REVERSE и PATINDEX, а затем сопоставить его со списком известных суффиксов.

Первые тестовые данные:

IF OBJECT_ID('tempdb..#names') IS NOT NULL DROP TABLE #names
IF OBJECT_ID('tempdb..#suffixes') IS NOT NULL DROP TABLE #suffixes
CREATE TABLE #names (name VARCHAR(32))
CREATE TABLE #suffixes (suffix VARCHAR(32))
GO

INSERT #names VALUES ('BRUNNING, II' )
INSERT #names VALUES ('BURCH II'     )
INSERT #names VALUES ('BUSS, JR.'    )
INSERT #names VALUES ('CANI III'     )
INSERT #names VALUES ('CHRISTIAN,SR' )
INSERT #names VALUES ('COLVIN Jr'    )
INSERT #names VALUES ('COWHERD,JR.'  )
INSERT #names VALUES ('BILLY BOB'    )
INSERT #names VALUES ('JOHNNY'       )

INSERT #suffixes VALUES ('II' )
INSERT #suffixes VALUES ('III')
INSERT #suffixes VALUES ('JR' )
INSERT #suffixes VALUES ('SR' )

Затем встроенная версия SELECT. Обратите внимание на использование NULLIF для контроля ошибок SUBSTRING.

SELECT
  name
, left_segments 
, right_segment
, new_name = CASE WHEN b.suffix IS NOT NULL THEN a.left_segments ELSE a.name END
, b.suffix
FROM (
  SELECT 
    name
  , left_segments = CASE WHEN left_segments LIKE '%[ ,]' THEN LEFT(left_segments,LEN(left_segments)-1) ELSE left_segments END
  , right_segment = CASE WHEN right_segment LIKE '%[.]' THEN LEFT(right_segment,LEN(right_segment)-1) ELSE right_segment END
  FROM (
    SELECT * 
    , left_segments = RTRIM(LEFT(RTRIM(name),LEN(name)-NULLIF(PATINDEX('%[ ,]%',REVERSE(RTRIM(name))),0)))
    , right_segment = RIGHT(RTRIM(name),NULLIF(PATINDEX('%[ ,]%',REVERSE(RTRIM(name))),0)-1)
    FROM #names
    ) a
  ) a
LEFT JOIN #suffixes b ON a.right_segment = b.suffix

Альтернативно UPDATE с локальными переменными:

ALTER TABLE #names ADD 
  left_segments VARCHAR(64)
, right_segment VARCHAR(64)
GO

DECLARE 
  @name VARCHAR(64)
, @len INT
, @last_delim INT
, @left_segments VARCHAR(64)
, @right_segment VARCHAR(64)

UPDATE #names SET 
  @name           = RTRIM(name)
, @len            = LEN(@name)
, @last_delim     = @len-NULLIF(PATINDEX('%[ ,]%',REVERSE(@name)),0)
, @left_segments  = RTRIM(LEFT(@name,@last_delim))
, @right_segment  = RIGHT(@name,@len-@last_delim-1)
, @left_segments  = CASE WHEN @left_segments LIKE '%[ ,]' THEN LEFT(@left_segments,LEN(@left_segments)-1) ELSE @left_segments END
, @right_segment  = CASE WHEN @right_segment LIKE '%[.]'  THEN LEFT(@right_segment,LEN(@right_segment)-1) ELSE @right_segment END
, left_segments   = @left_segments
, right_segment   = @right_segment

SELECT a.*
, new_name = CASE WHEN b.suffix IS NOT NULL THEN a.left_segments ELSE a.name END
, suffix = b.suffix
FROM #names a LEFT JOIN #suffixes b ON a.right_segment = b.suffix

Встроенный SELECT довольно удобен, но труден для чтения и устранения неполадок. Я предпочитаю UPDATE с локальными переменными для всего, к чему мне, возможно, придется вернуться позже. Кроме того, он облегчает применение отдельных правок.

EDIT , SELECT метод, слегка отредактированный и обернутый в встроенную табличную функцию . Встроенный TVF должен быть более эффективным, чем скалярный UDF, и вы получите несколько возвращаемых значений для загрузки.

CREATE FUNCTION dbo.ParseNameAndSuffix (@name VARCHAR(64), @ValidSuffixes VARCHAR(512))
RETURNS TABLE AS RETURN (
  SELECT
    left_segments 
  , right_segment
  , new_name = CASE WHEN CHARINDEX(';'+right_segment+';',';'+@ValidSuffixes+';') > 0 THEN a.left_segments ELSE a.name END
  , suffix   = CASE WHEN CHARINDEX(';'+right_segment+';',';'+@ValidSuffixes+';') > 0 THEN a.right_segment END
  FROM (
    SELECT 
      name
    , left_segments = CASE WHEN left_segments LIKE '%[ ,]' THEN LEFT(left_segments,LEN(left_segments)-1) ELSE left_segments END
    , right_segment = CASE WHEN right_segment LIKE '%[.]' THEN LEFT(right_segment,LEN(right_segment)-1) ELSE right_segment END
    FROM (
      SELECT name
      , left_segments = RTRIM(LEFT(name,LEN(name)-NULLIF(PATINDEX('%[ ,]%',REVERSE(name)),0)))
      , right_segment = RIGHT(name,NULLIF(PATINDEX('%[ ,]%',REVERSE(name)),0)-1)
      FROM (SELECT name = LTRIM(RTRIM(@name))) a
      ) a
    ) a
  )
GO

SELECT * FROM #names a
CROSS APPLY dbo.ParseNameAndSuffix(a.name,'II;III;JR;SR') b
1 голос
/ 14 сентября 2010

Вне моей головы, так как у вас есть небольшое количество замен, вы можете сделать что-то вроде этого:

ОБНОВЛЕНИЕ [TableName] SET LastName = SUBSTRING (LastName, 0, CHARINDEX (фамилия), 'III')), SUFFIX = 'III', где CHARINDEX (фамилия, 'III')> 0;

1 голос
/ 14 сентября 2010

Возможно, вы захотите выполнить некоторую предварительную обработку, чтобы сделать форматы более согласованными.

Попробуйте удалить конечный период и заменить все запятые пробелом. После этого ваш образец должен выглядеть так:

LastName
BRUNNING  II
BURCH II
BUSS  JR
CANI III
CHRISTIAN SR
COLVIN Jr
COWHERD JR

Затем вы можете идентифицировать строки, оканчивающиеся на «I», «II», «III», «JR» и «SR», вырезать их суффикс в соответствии с его длиной и обновить поле «Суффикс» требуемым значением.

0 голосов
/ 14 сентября 2010

Я думаю, что вашей лучшей ставкой будет совпадение с RegEx для последнего слова (исключая знаки препинания) в списке (JR, Sr, III и т. Д.)

Проверьте этот блог

http://blogs.msdn.com/b/khen1234/archive/2005/05/11/416392.aspx

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