2016-10-05 51 views
3

我要求包含字段ComNo,如果字段长度超过5个字符,则Comment中的其余字符应显示在下一行,并且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数据类型,最好是使用dbms_lob版本的substr。另外,如果您必须将数据切分为75个字符,则必须调整多个数字。下面是相同的解决方案,这两个更改没有ORDER BY子句(如果用于将数据迁移到另一个db产品,则不需要)。注意:与通常的substr()函数相比,dbms_lob.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将字符串限制为4,000个字符,所以如果它们比这更长,我会感到惊讶。 –

+0

@GordonLinoff - CLOB数据类型的Oracle文档:https://docs.oracle.com/cd/B28359_01/server.111/b28318/datatype。htm#i3237 – mathguy