Разбор строки описания для заполнения пустых полей - PullRequest
0 голосов
/ 01 декабря 2018

Informix 12.10

tblItems
(
Type        SMALLINT,       {Precious Metal = 1, Other = 2}
Description VARCHAR,
Quantity    SMALLINT,
Name        VARCHAR,
Weight      DECIMAL(5,1),
Purity      SMALLINT,
Brand       VARCHAR,
Model       VARCHAR,
SerialNum   VARCHAR
);

ОБНОВЛЕНИЕ РЕДАКТИРОВАНИЯ: Образцы данных ниже хранятся в tblItems.Type и tblItems.Description.Обратите внимание, что содержимое столбца «Описание» состоит из прописных букв и может также включать знаки пунктуации.

2|1LAPTOP APPLE 15.5" MODEL MACKBOOK PRO,S/N W80461WCAGX, WITH CHARGER||||||||
1|1RING 2.3PW 14K||||||||
2|DRILL RIOBY, MODEL D5521 S/N77720||||||||
2|TRIMMER TORO, MODEL 0242 S/N 66759||||||||
2|CELL SAMSUNG NOTE3, MODEL SM-N900T S/N RV8F90YLZ9W||||||||

Мне нужно проанализировать описания образцов элементов в столбцах ниже, используя правила, упомянутые в комментариях:

Quantity,      {if description string does not start with a number, then Quantity = 1}
Name,          {Always the first element if description has no quantity, second element if quantity present] 
Weight,        {Always before "PW" if Type = 1, Default to zero if Type = 2}
Purity,        {Always before "K" if Type = 1, Default to NULL if Type = 2} 
Brand,         {Always the second element in description, if present} 
Model,         {Always after "MODEL", with or without a space}
Serial Number  {Always after "S/N", with or without a space}

Я хотел бы сделать это с помощью оператора UPDATE,но если в Informix есть утилита импорта, такая как SSIS SQL-Server, то это может быть лучшим вариантом.

ОБНОВЛЕНИЕ, Ожидаемые результаты:

Quantity   1               1       1        1         1
Name       LAPTOP          RING    DRILL    TRIMMER   CELL
Weight     0.0             2.3     0.0      0.0       0.0
Purity                     14
Brand      APPLE                   RIOBY    TORO      SAMSUNG
Model      MACKBOOK PRO            D5521    0242      SM-N900T
SerialNum  W8046WCAGX              77720    66759     RV8F90YLZ9W

Ответы [ 2 ]

0 голосов
/ 05 декабря 2018

Если вы ищете опцию SQL Server и открыты для функции разделения / анализа, которая поддерживает последовательность

Пример

Select A.Type
      ,A.Description
      ,C.*
 From  YourTable A
 Cross Apply (values ( replace(
                       replace(
                       replace(
                       replace(A.Description,',',' ')
                       ,'  ',' ')
                       ,'Model ','Model')
                       ,'S/N ','S/N')
                     ) 
             )B(CleanString)

 Cross Apply (
                Select Quantity  = IsNull(left(max(case when RetSeq=1 then RetVal end),NullIf(patindex('%[^0-9]%',max(case when RetSeq=1 then RetVal end)) -1,0)),1)
                      ,Name      = substring(max(case when RetSeq=1 then RetVal end),patindex('%[^0-9]%',max(case when RetSeq=1 then RetVal end)),charindex(' ',max(case when RetSeq=1 then RetVal end)+' ')-1)
                      ,Weight    = IIF(A.Type=2,null,try_convert(decimal(5,1),replace(max(case when RetVal like '%PW' then RetVal end),'PW','')))
                      ,Purity    = try_convert(smallint    ,replace(max(case when RetVal like '%K'  then RetVal end),'K',''))
                      ,Brand     = IIF(A.Type=1,null,max(case when RetSeq=2 then RetVal end))
                      ,Model     = replace(max(case when RetVal Like 'Model[0-9,A-Z]%' then RetVal end),'Model','')
                      ,SerialNum = replace(max(case when RetVal Like 'S/N[0-9,A-Z]%' then RetVal end),'S/N','')
                 From [dbo].[tvf-Str-Parse](CleanString,' ') B1
             ) C

Возвращает

enter image description here

TVF, если интересно

CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table 
As
Return (  
    Select RetSeq = Row_Number() over (Order By (Select null))
          ,RetVal = LTrim(RTrim(B.i.value('(./text())[1]', 'varchar(max)')))
    From  (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
    Cross Apply x.nodes('x') AS B(i)
);

РЕДАКТИРОВАТЬ - Если вы не хотите или не можете использовать TVF

dbFiddle

Select A.Type
      ,A.Description
      ,C.*
 From  YourTable A
 Cross Apply (values ( replace(
                       replace(
                       replace(
                       replace(A.Description,',',' ')
                       ,'  ',' ')
                       ,'Model ','Model')
                       ,'S/N ','S/N')
                     ) 
             )B(CleanString)

 Cross Apply (
                Select Quantity  = IsNull(left(max(case when RetSeq=1 then RetVal end),NullIf(patindex('%[^0-9]%',max(case when RetSeq=1 then RetVal end)) -1,0)),1)
                      ,Name      = substring(max(case when RetSeq=1 then RetVal end),patindex('%[^0-9]%',max(case when RetSeq=1 then RetVal end)),charindex(' ',max(case when RetSeq=1 then RetVal end)+' ')-1)
                      ,Weight    = IIF(A.Type=2,null,try_convert(decimal(5,1),replace(max(case when RetVal like '%PW' then RetVal end),'PW','')))
                      ,Purity    = try_convert(smallint    ,replace(max(case when RetVal like '%K'  then RetVal end),'K',''))
                      ,Brand     = IIF(A.Type=1,null,max(case when RetSeq=2 then RetVal end))
                      ,Model     = replace(max(case when RetVal Like 'Model[0-9,A-Z]%' then RetVal end),'Model','')
                      ,SerialNum = replace(max(case when RetVal Like 'S/N[0-9,A-Z]%' then RetVal end),'S/N','')
                 From  (
                        Select RetSeq = row_number() over (Order By (Select null))
                              ,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
                        From  (Select x = Cast('<x>' + replace((Select replace(CleanString,' ','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A 
                        Cross Apply x.nodes('x') AS B(i)
                       ) B1
             ) C
0 голосов
/ 02 декабря 2018

Если вы используете Informix 12.10.XC8 или выше, вы можете попробовать использовать регулярные выражения для разбора строки описания (см. Онлайн документацию здесь).

Серийный номер:например, вы можете сделать:

UPDATE tblitems
SET
serialnum = 
DECODE 
(
    regex_match(description, '(.*)(S\/N)(.*)', 3)
    , 't'::BOOLEAN, regex_replace(description, '(.*)(S\/N)([[:blank:]]?)([[:alnum:]]*)(.*)', '\4', 0, 3)
    , 'f'::BOOLEAN, ''
)

Итак, в предыдущем примере я проверяю, содержит ли описание строку S/N, и если это правда, я использую regex_replace, чтобы вернуть значение после нее,в этом случае 4-я группа соответствия в регулярном выражении (я не использую regex_extract, чтобы получить значение, потому что оно, кажется, возвращает несколько значений, и я получаю ошибку -686).

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

...