【问题标题】:Auto increment counter if field length is greater than n如果字段长度大于 n,则自动递增计数器
【发布时间】:2017-02-13 07:58:51
【问题描述】:

我被要求包含一个 ComNo 字段,如果 Comments 的字段长度大于 5 个字符,Comment 中的其余字符应出现在下一行,ComNo 字段应加一

输入

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 查询来实现吗?

【问题讨论】:

    标签: sql oracle auto-increment


    【解决方案1】:

    一个蛮力选项就是将 UNION 一次将 cmets 拆分为 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
    ...
    

    【讨论】:

    【解决方案2】:

    这是一种方法:

    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 个字符的 cmets,因此 n 只需要值 1 和 2。您可以通过扩展 n 创建更多行。

    【讨论】:

    • 嗨,戈登,感谢您的回复。我的示例 cmets 最多只有 10 个字符,但实际数据的 cmets 超过 4000 个字符。
    • @AnnieJeba 。 . .这个解决方案很容易扩展,以防万一。但是,我确实注意到,Oracle 将字符串限制为 4,000 个字符,所以如果它们比这更长,我会感到惊讶。
    • @GordonLinoff - CLOB 数据类型的 Oracle 文档:docs.oracle.com/cd/B28359_01/server.111/b28318/…
    • @AnnieJeba - 如果您的数据是 CLOB,您可能会受益于使用 dbms_lob 包(substrinstr 的“lob 版本”)。 docs.oracle.com/cd/B28359_01/appdev.111/b28419/… 问题:如果 cmets 可能是数千个字符,为什么要将它们分成五个字符片段?为什么是 5 个而不是 80 个?
    • 实际要求是将 cmets 切成每行 75 个字符,因为示例数据会很大,我刚才提到 5 个字符。他们正在将数据从 Oracle 加载到 SAP DB,SAP 中的字段长度限制为 75 个字符,因此我被要求根据他们将数据加载到 SAP 的方式来提取报告
    【解决方案3】:

    这是一个对 cme​​ts 的长度没有预先假设的解决方案。我添加了两个字符串,一个短(少于 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 子句(如果用于将数据迁移到另一个数据库产品则不需要)。注意: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
    ;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-02-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多