Как скопировать строку и разбить один из столбцов на основе определенных критериев в Oracle SQL? - PullRequest
0 голосов
/ 01 февраля 2020

У меня есть таблица данных на 250 тыс., И из этих данных у меня есть 1000 строк с одинаковыми данными в каждой строке столбца, один ссылочный столбец, который отличается. Ниже приведен пример:

Name   | Tel_No     | Post_Code | Ref_No
Damian | 7900123456 | ME1 2BC   | 12345678 1234567891234
Graeme | 7900789012 | ME1 2DE   | 12 345 5678901234567
Sarah  | 7900456789 | ME1 2FG   | 90123456 890123456789

Теперь я хотел бы сделать для каждой строки, где ссылка имеет число 8 di git, затем пробел, а затем число 13 di git, Я хотел бы скопировать эту строку, но разделить ref_no, чтобы у меня была одна строка с 8 di git ref_no и 1 с 13 di git.

В приведенном выше примере код должен работать только с первой строкой, поскольку Graeme не удовлетворяет этому критерию, поскольку ref_no имеет 2 цифры, а затем пробел, поэтому код должен сразу потерпеть неудачу. Для Сары код потерпит неудачу, так как ref_no для 2-ой части имеет только 12 цифр, а не 13. Для Грэма и Сары их данные будут оставаться в отдельных строках с ref_no, который у них есть. нужно было сделать с помощью регулярных выражений, чтобы найти подходящий шаблон, к сожалению, я еще не пробовал какой-либо код, так как он снова для меня новый, и копирование строки слегка выкинуло меня, поскольку я не делал что-то подобное раньше, поэтому Вот несколько советов по передовой практике для продвижения вперед.

Кстати, вот как это должно выглядеть в таблице (у меня есть столбец автоидентификатора, поэтому новым строкам также будут назначаться новые идентификаторы):

Name   | Tel_No     | Post_Code | Ref_No
Damian | 7900123456 | ME1 2BC   | 12345678
Damian | 7900123456 | ME1 2BC   | 1234567891234

Заранее спасибо.

РЕДАКТИРОВАТЬ 04/02/2020 -----------------------

Извините за задержку, к сожалению, не слишком хорошо. Спасибо, ребята за все ваши ответы. Yunnosch, Wiktor, Rob as request: Вот моя таблица создания и вставки утверждений, и именно то, что я ищу, просто чтобы было намного понятнее то, что я спрашиваю. Извинения должны были быть включены в начале.

Создать таблицу:

CREATE TABLE "BU_TABLE" 
   (    "ID" NUMBER NOT NULL ENABLE, 
    "NAME" VARCHAR2(255 BYTE), 
    "TEL_NO" VARCHAR2(255 BYTE), 
    "POST_CODE" VARCHAR2(8 BYTE), 
    "REF_NO" VARCHAR2(255 BYTE), 
     CONSTRAINT "TABLE1_PK" PRIMARY KEY ("ID")
;

Причина, по которой я установил столбцы Tel_No и Ref_No как Varchar2, заключается в том, что у чисел есть пробелы, тогда a) он выдаст сообщение об ошибке неверного номера. b) Tel_No в данный момент с данными примера не имеет этой проблемы, но по мере добавления дополнительных данных эта проблема может возникнуть в будущем.

Мои инструкции вставки:

Insert into BU_TABLE (ID,NAME,TEL_NO,POST_CODE,REF_NO) values (1,'Damian','7900123456','ME1 2BC','12345678 1234567891234');
Insert into BU_TABLE (ID,NAME,TEL_NO,POST_CODE,REF_NO) values (2,'Graeme','7900789012','ME1 2DE','12 345 5678901234567');
Insert into BU_TABLE (ID,NAME,TEL_NO,POST_CODE,REF_NO) values (3,'Sarah','7900456789','ME1 2FG','90123456 890123456789');

Теперь мне бы хотелось, чтобы BU_TABLE оставался без изменений с необработанными данными. Я хотел бы создать еще одну таблицу на обратной стороне этой таблицы, чтобы разделить Ref_No, поэтому у меня есть последовательность из 8 чисел, пробел и затем 13 чисел. Где бы ни происходил этот шаблон, я хотел бы продублировать строку, создать новый идентификатор (следующий доступный) и дать мне следующее:

Что бы я хотел:

Name   | Tel_No     | Post_Code | Ref_No
Damian | 7900123456 | ME1 2BC   | 12345678
Damian | 7900123456 | ME1 2BC   | 1234567891234

Строки, в которых требуемый код не нашел последовательность, строки данных в таблице останутся прежними, поэтому моя итоговая таблица будет выглядеть следующим образом:

Final Table

ID | Name   | Tel_No     | Post_Code | Ref_No
2 | Graeme | 7900789012 | ME1 2DE   | 12 345 5678901234567
3 | Sarah  | 7900456789 | ME1 2FG   | 90123456 890123456789
4 | Damian | 7900123456 | ME1 2BC   | 12345678
5 | Damian | 7900123456 | ME1 2BC   | 1234567891234

Надеюсь, это сделает его намного яснее о том, что я пытаюсь сделать.

Ответы [ 3 ]

0 голосов
/ 01 февраля 2020

Даже без регулярных выражений вы можете получить две строки по следующим критериям:

with data
  as (
        select '12345678 1234567890123' as x /*This matches the 8<SPACE>13*/
         from dual
        union all
        select '1234567 1234567890123' as x
         from dual
     ) 
   ,criteria_data
    as (
        select t.*
               ,substr(x,1,instr(x,' ')) as first_part
               ,substr(x,instr(x,' ')+1,length(x)) as second_part
          from data t
         where length(x)-length(replace(x,' ',''))=1  /*Check for exactly one space*/
           and length(substr(x,1,instr(x,' ')))=8 /*check for first segment with 8 char*/
           and length(substr(x,instr(x,' ')+1,length(x)))=13 /*Check for second segment with 13 char length*/
       )
select a.*,case when lvl=1 then first_part when lvl=2 then second_part end as ref_no 
  from criteria_data a
  join (select level as lvl 
          from dual 
        connect by level<=2) b
    on 1=1
0 голосов
/ 01 февраля 2020

Вы можете использовать функции regexp_substr() и substr() вместе для взаимного сравнения, равны ли разделенные части. А затем сгенерируйте еще одну строку для каждой строки, удовлетворяющей условию where:

with t as
(
select regexp_substr(Ref_No,'[[:digit:]]{8}+') as Ref_No1_0,
       regexp_substr(Ref_No,'[^[:space:]]+$') as Ref_No2_0,
       substr(Ref_No,1,8) as Ref_No1_1 , substr(Ref_No,-13) as Ref_No2_1,
       t.*
  from tab t
)
select Name , Tel_No , Post_Code , 
       case when lvl = 1 then Ref_No1_0 
            when lvl = 2 then Ref_No2_0 end as Ref_No       
  from t
 cross join (select level as lvl from dual connect by level <= 2) 
 where Ref_No1_0 = Ref_No1_1 
   and Ref_No2_0 = Ref_No2_1 

Или напрямую используйте regexp_like() (вместе с substr()) функциями в условии where:

select Name , Tel_No , Post_Code , 
       case when lvl = 1 then substr(Ref_No,1,8) 
            when lvl = 2 then substr(Ref_No,-13) end as Ref_No
  from tab
 cross join (select level as lvl from dual connect by level <= 2)   
 where regexp_like(substr(Ref_No,1,8),'[[:digit:]]{8}') 
   and regexp_like(substr(Ref_No,-13),'[[:digit:]]{13}') 

Демо

0 голосов
/ 01 февраля 2020

Этот метод, как вы можете разделить, я добавлю полный код:
Это для первых 8 ди git:

select substr(ref_no,0,8) from stack where instr(ref_no,' ') >= 9;

Полный код =>

with 
tb_split8 as (
select Name, substr(ref_no,0,8) as split8 from stack where instr(ref_no,' ') >= 9),
tb_split13 as( 
select Name, substr(ref_no,10,13) as split13 from stack where instr(ref_no,' ',10) = 0 and length(substr(ref_no,10,13)) = 13)
select a.Name, Post_code, Tel_no, split8, split13 from stack a join tb_split8 b on a.Name = b.Name join tb_split13 c on b.Name = c.Name ;

Я проверил в жабе, что это работа.

enter image description here

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