2016-10-05 7 views
3

Меня попросили включить поле ComNo, и если длина поля комментариев больше 5 символов, остальные символы в комментарии должны появиться в следующей строке, а поле ComNo должно увеличивается на одинСчетчик автоинкремента, если длина поля больше n

вход

EmpID EmpName ServiceNumber Date   Comments 
1  a  123   23-03-1990 wednesday 
1  a  1234   24-04-1990 Test12 
2  b  234   24-05-2016 Todayis 

И ожидаемый выход

EmpID EmpName ServiceNumber Date  ComNo Comments 
1  a  123   23-03-1990 1  wedne 
1  a  123   23-03-1990 2  sday 
1  a  1234   24-04-1990 1  Test1 
1  a  1234   24-04-1990 2  2 
2  b  234   24-05-2016 1  Today 
2  b  234   24-05-2016 2  is 

у меня есть идея, как реализовать это с помощью процедуры PLSQL но можем ли мы реализовать то же самое с использованием SQL-запроса?

ответ

2

Вот решение, которое не делает предварительных предположений о длине комментариев. Я добавил две строки, одну короткую (менее 5 символов) и одну длиннее 10 символов, а также одну с комментарием NULL, чтобы убедиться, что строка не потеряна, чтобы тщательно протестировать решение.

Я предполагаю, что (empid, dt) - это уникальная комбинация (возможно, первичный ключ) в базовой таблице. Кстати, надеюсь, вы фактически не используете Date в качестве имени столбца в вашей схеме.

Решение не содержит предложение WITH; он начинается с select empid... Предложение ORDER BY может также не понадобиться.

with 
    test_data (empid, empname, servicenumber, dt, comments) as (
     select 1, 'a', 123, to_date('23-03-1990', 'dd-mm-yyyy'), 'wednesday' from dual union all 
     select 1, 'a', 1234, to_date('24-04-1990', 'dd-mm-yyyy'), 'Test12'  from dual union all 
     select 2, 'b', 234, to_date('24-05-2016', 'dd-mm-yyyy'), 'Todayis'  from dual union all 
     select 2, 'b', 235, to_date('25-05-2016', 'dd-mm-yyyy'), 'Joe'   from dual union all 
     select 3, 'c', 238, to_date('25-05-2016', 'dd-mm-yyyy'), ''   from dual union all 
     select 4, 'c', 2238, to_date('25-05-2016', 'dd-mm-yyyy'), 'longer string' from dual 
    ) 
select empid, empname, servicenumber, dt, level as comno, 
     substr(comments, 5 * level - 4, 5) as comments 
from test_data 
connect by level <= 1 + length(comments)/5 
    and prior empid = empid 
    and prior dt = dt 
    and prior sys_guid() is not null 
order by empid, dt 
; 

    EMPID E SERVICENUMBER DT    COMNO COMMENTS 
---------- - ------------- ---------- ---------- -------------------- 
     1 a   123 1990-03-23   1 wedne 
     1 a   123 1990-03-23   2 sday 
     1 a   1234 1990-04-24   1 Test1 
     1 a   1234 1990-04-24   2 2 
     2 b   234 2016-05-24   1 Today 
     2 b   234 2016-05-24   2 is 
     2 b   235 2016-05-25   1 Joe 
     3 c   238 2016-05-25   1 
     4 c   2238 2016-05-25   1 longe 
     4 c   2238 2016-05-25   2 r str 
     4 c   2238 2016-05-25   3 ing 

Добавлено: Если данные типа CLOB данных, то лучше использовать версию substrdbms_lob. Кроме того, если вы должны нарезать данные на 75 символьных сегментов, вы должны отрегулировать несколько номеров. Вот то же самое решение с этими двумя изменениями и без предложения ORDER BY (не требуется, если это используется для переноса данных на другой продукт db). ПРИМЕЧАНИЕ: dbms_lob.substr() имеет «количество» и «смещение» (второй и третий аргументы) в обратном порядке по сравнению с обычной функцией substr(); обратите внимание, что при сравнении решений.

select empid, empname, servicenumber, dt, level as comno, 
     dbms_lob.substr(comments, 75, 75 * level - 74) as comments 
from test_data 
connect by level <= 1 + length(comments)/75 
    and prior empid = empid 
    and prior dt = dt 
    and prior sys_guid() is not null 
; 
+0

Спасибо :) Это работает –

0

скотина вариант сила будет просто UNION вместе записи в результате разделения комментариев от 5 символов в то время:

SELECT EmpID, EmpName, ServiceNumber, Date, 1, SUBSTR(Comments, 1, 5) AS Comments 
FROM yourTable 
UNION ALL 
SELECT EmpID, EmpName, ServiceNumber, Date, 2, SUBSTR(Comments, 6, 5) AS Comments 
FROM yourTable 
WHERE SUBSTR(Comments, 6, 5) <> '' -- but don't show a record if 
UNION ALL       -- all characters already used 
... 
+0

@AnnieJeba Затем взгляните на ответ Гордона. Кстати, зачем вам это нужно? –

+0

http://docs.oracle.com/cd/E11882_01/server.112/e41084/functions181.htm#SQLRF06114 – mathguy

+0

@mathguy Почему я думал, что OP использовал Postgres? –

0

Вот один из способов сделать это:

with n as (
     select 1 as n from dual union all 
     select 2 from dual 
    ) 
select EmpID, EmpName, ServiceNumber, Date, ComNo, 
     substr(comments, n.n * 5 - 4, 5) as Comments 
from t join 
    n 
    on length(comments) >= n.n * 5 + 1; 

Примечание. В вашем примере есть только комментарии до 10 символов, поэтому для n нужны только значения 1 и 2. Вы можете создавать дополнительные строки, расширяя n.

+0

Привет, Гордон, спасибо за ваш ответ. Мой пример имеет комментарии только до 10 символов, но фактические данные содержат комментарии более 4000 символов. –

+0

@ AnnieJeba. , , Это решение легко распространяется на случай, если это так. Однако я отмечаю, что Oracle ограничивает строки до 4000 символов, поэтому я был бы удивлен, если они будут длиннее этого. –

+0

@GordonLinoff - документация Oracle для типа данных CLOB: https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype.htm # i3237 – mathguy