【问题标题】:Oracle - Format and structure data / queryOracle - 格式化和结构数据/查询
【发布时间】:2018-12-15 17:29:04
【问题描述】:

这是我挑战 SQL (Oracle) 的第一周。我以前从未真正使用过 SQL。只尝试理解查询。目前我正在尝试通过服务器端的 SQL (Oracle) 外包一个查询,到目前为止我已经在 Excel(电源查询)中进行了转换,以获得相应的性能改进。这意味着到目前为止我已经实现了电源查询中的步骤,并尝试使用 SQL 语句来实现它们。我已经在这里问了几个问题,也从你那里得到了很多帮助和好主意。我认为在一个问题中处理所有事情最有意义。原始表或数据库的结构如下所示:

名称 = 值示例

  • JDDate = 118001
  • 列表项
  • START = 63000(06:30:00)
  • END = 240000(对于 24:00:00)
  • NR = 34000001
  • 终端 = MM01X11
  • Dep = XX01
  • 文档 = 1000800001
  • 类型 = 1
  • Key1 = 99000000
  • Key2 = 99000000

  • 首先,我需要所有“Typ” = 1 且 JDDate =>118000 的值

WHERE "JDDate" >118000 AND“类型”= 1

  • 然后我需要基于正确的 JDDate/ 格式的 START 和 END 之间的差异/时间步长。不幸的是,这里有一些重复,基于 JDDate,START;结尾;终端:

.

cte (staff_nr, start_datetime, end_datetime) as (
  select distinct ltrim(substr("NR", -6), '0'),
      date '1900-01-01'
        + floor("JDDate" / 1000) * interval '1' year
        + (mod("JDDate", 1000) -1) * interval '1' day
        + floor("START" / 10000) * interval '1' hour
        + floor(mod("START", 10000) / 100) * interval '1' minute
        + mod("START", 100) * interval '1' second,
      date '1900-01-01'
        + floor("JDDate" / 1000) * interval '1' year
        + (mod("JDDate", 1000) -1) * interval '1' day
        + case when "END" = 240000 then interval '1' day
               else floor("END" / 10000) * interval '1' hour
                  + floor(mod("END", 10000) / 100) * interval '1' minute
                  + mod("END", 100) * interval '1' second
          end
FROM "POOL0101"."9909KK"
WHERE   "JDDate" >118000
    AND "Typ" = 1

)
select staff_nr,
  to_char(start_datetime, 'YYYY-MM-DD HH24:MI:SS') as end_datetime,
  to_char(end_datetime, 'YYYY-MM-DD HH24:MI:SS') as end_datetime,
  end_datetime - start_datetime as diff_in_days
from cte
  • 至少我在 Key1 和 Key2 有一些过时的数据/重复项。所以 Key1 每次都包含一个数字。 Key2 包含一个 0 或一个数字,它也是 Key1 中的一个数字。如果 Key1 和 Key2 中的数字相同,则应删除这两行。

有人可以帮我把所有这些元素都写到 SQL 上吗?

有没有办法向您展示一个示例数据库?

最好的问候 约书亚

【问题讨论】:

    标签: sql oracle


    【解决方案1】:

    有没有办法向您展示一个示例数据库?

    您可以使用dbfiddle.uk 创建测试表和查询。 假设您有以下测试表(称为 ORIGINAL)和数据:

    表格

    create table original (
      jddate number
    , starttime timestamp
    , endtime timestamp
    , nr number
    , terminal varchar2( 100 )
    , dep varchar2( 100 )
    , doc number
    , typ number
    , key1 number
    , key2 number 
    ) ;
    

    插入

    insert into original
    select 118001
    , trunc( sysdate ) + ( 6/24 ) + ( 30/(24*60 ) )
    , trunc( sysdate ) + (86399/86400)
    , 34000001, 'MM01X11', 'XX01', 1000800001, 1, 99000000, 99000000  from dual union all 
    -- duplicate
    select 118001
    , trunc( sysdate ) + ( 6/24 ) + ( 30/(24*60 ) )
    , trunc( sysdate ) + (86399/86400)
    , 34000001, 'MM01X11', 'XX01', 1000800001, 1, 99000000, 99111111  from dual union all 
    select 118001
    , trunc( sysdate ) + ( 6/24 ) + ( 30/(24*60 ) )
    , trunc( sysdate ) + (86399/86400)
    , 34000001, 'MM01X11', 'XX01', 1000800001, 1, 99000000, 99111111  from dual union all 
    --
    select 118001
    , trunc( sysdate ) + ( 6/24 ) + ( 30/(24*60 ) )
    , trunc( sysdate ) + (86399/86400)
    , 34000001, 'MM01X11', 'XX01', 1000800001, 2, 99000000, 99000000  from dual union all 
    select 118001
    , trunc( sysdate ) + ( 6/24 ) + ( 30/(24*60 ) )
    , trunc( sysdate ) + (86399/86400)
    , 34000001, 'MM01X11', 'XX01', 1000800001, 3, 99000000, 99000000  from dual union all 
    select 118001
    , trunc( sysdate ) + ( 6/24 ) + ( 30/(24*60 ) )
    , trunc( sysdate ) + (86399/86400)
    , 34000001, 'MM01X11', 'XX01', 1000800001, 4, 99000000, 99000000  from dual ;
    

    选择

    -- select * from original;    
    JDDATE  STARTTIME                     ENDTIME                       NR        TERMINAL  DEP   DOC         TYP  KEY1      KEY2      
        118001  15-DEC-18 06.30.00.000000000  15-DEC-18 23.59.59.000000000  34000001  MM01X11   XX01  1000800001  1    99000000  99000000  
        118001  15-DEC-18 06.30.00.000000000  15-DEC-18 23.59.59.000000000  34000001  MM01X11   XX01  1000800001  1    99000000  99111111  
        118001  15-DEC-18 06.30.00.000000000  15-DEC-18 23.59.59.000000000  34000001  MM01X11   XX01  1000800001  1    99000000  99111111  
        118001  15-DEC-18 06.30.00.000000000  15-DEC-18 23.59.59.000000000  34000001  MM01X11   XX01  1000800001  2    99000000  99000000  
        118001  15-DEC-18 06.30.00.000000000  15-DEC-18 23.59.59.000000000  34000001  MM01X11   XX01  1000800001  3    99000000  99000000  
        118001  15-DEC-18 06.30.00.000000000  15-DEC-18 23.59.59.000000000  34000001  MM01X11   XX01  1000800001  4    99000000  99000000  
    

    要求

    {1} 起初我需要“Typ” = 1 和 JDDate =>118000 的所有值

    {2} 然后我需要基于 START 和 END 之间的差异/时间步长 在正确的 JDDate/ 格式中。不幸的是,这里有一些重复, 基于JDDate,START;结尾;终端:

    {3} 至少我在 Key1 和 键 2。所以 Key1 每次都包含一个数字。 Key2 包含 一个 0 或一个数字,它也是 Key1 中的一个数字。如果在 Key1 中 和 Key2 是相同的数字,两行都应该删除。

    示例查询 - 作为起点(WHERE 子句将需要更多工作......)

    select distinct                    -- {2} remove duplicates
      jddate
    , endtime - starttime as interval_ -- {2} 
    , nr
    , terminal
    , dep
    , doc
    , typ
    , key1
    , key2
    from original 
    where typ = 1 and jddate > 118000  -- {1}
      and key1 <> key2                 -- {3}
    ; 
    
    -- result
    JDDATE  INTERVAL_            NR        TERMINAL  DEP   DOC         TYP  KEY1      KEY2      
    118001  +00 17:29:59.000000  34000001  MM01X11   XX01  1000800001  1    99000000  99111111 
    

    为了将 JDDATE 列中的值转换为 Oracle DATE,您可以使用您之前获得的 answer 的代码创建一个小函数。 (您不必这样做,但它会从您的 SELECT 中删除一些“混乱”)例如

    --  https://stackoverflow.com/questions/53743601/sql-julien-date-cyyddd-to-date
    /*
    select date '1900-01-01'
      + floor(118001 / 1000) * interval '1' year
      + (mod(118001, 1000) - 1) * interval '1' day
    from dual;
    */
    
    -- this is far from perfect, needs range checking, exception handling etc
    create or replace function cyyddd_to_date ( cyyddd number ) return date
    is
    begin
      return 
        date '1900-01-01' 
      + floor( cyyddd / 1000 ) * interval '1' year 
      + ( mod( cyyddd, 1000 ) - 1 ) * interval '1' day
      ;
    end;
    /
    
    -- quick test
    select 
      cyyddd_to_date( 118001 ) date_
    , to_char( cyyddd_to_date( 118001 ), 'YYYY-MM-DD' ) datetime_
    from dual; 
    
    -- result
    DATE_      DATETIME_   
    01-JAN-18  2018-01-01
    

    最终查询

    select distinct                    -- {2} remove duplicates
      to_char( cyyddd_to_date( jddate ), 'YYYY-MM-DD' ) date_
    , endtime - starttime  interval_   -- {2} 
    , nr
    , terminal
    , dep
    , doc
    , typ
    , key1
    , key2
    from original 
    where typ = 1 and jddate > 118000  -- {1}
      and key1 <> key2                 -- {3}
    ; 
    
    -- result
    DATE_       INTERVAL_            NR        TERMINAL  DEP   DOC         TYP  KEY1      KEY2      
    2018-01-01  +00 17:29:59.000000  34000001  MM01X11   XX01  1000800001  1    99000000  99111111 
    

    使用 Oracle 12c 和 Oracle 11g 测试,dbfiddle here

    【讨论】:

    • 斯特凡!非常感谢!我需要一些时间来捕捉一切。那我就留言吧!
    • 感谢您的反馈!关于这一点还有很多很多要说(我不得不停止在某处写...)。通常,使用内置 (Oracle) 数据类型和函数(请参阅 docs.oracle.com/database/121/NLSPG/ch4datetime.htm)
    猜你喜欢
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    相关资源
    最近更新 更多