Sql 如何编写一个程序以获得所需的输出?

Sql 如何编写一个程序以获得所需的输出?,sql,oracle,plsql,Sql,Oracle,Plsql,现有数据: A VALID_FROM VALID_TO ------------ ----------- ----------- ARN-1 01-APR-2015 31-DEC-9999 ARN-1 01-MAY-2015 31-DEC-9999 ARN-1 01-JUN-2015 31-DEC-9999 所需输出: A VALID_FROM VALID

现有数据:

A              VALID_FROM    VALID_TO
------------   -----------   -----------
ARN-1          01-APR-2015   31-DEC-9999
ARN-1          01-MAY-2015   31-DEC-9999
ARN-1          01-JUN-2015   31-DEC-9999 
所需输出:

A              VALID_FROM    VALID_TO
------------   -----------   -----------
ARN-1          01-APR-2015   30-APR-2015
ARN-1          01-MAY-2015   31-MAY-2015
ARN-1          01-JUN-2015   31-DEC-9999

如何编写Oracle PL/SQL过程来获得此输出?

您可能需要以下内容:

insert into tableB
select A,
       valid_from,
       nvl(lead(valid_from)  over (partition by a order by valid_from asc) -1, valid_to)
from tableA

这将插入第二个表中的所有行,为每一行计算有效性结束(如果存在);如果不存在,则使用行中已存在的结束日期。

不需要PL/SQL,您可以在纯SQL中执行

您需要使用LAST_DAY函数从
列获取
VALID_中日期值的当月最后一天行号仅用于处理最长日期的情况,即您需要神奇的日期
9999年12月31日

SQL> WITH sample_data AS(
  2  SELECT 'ARN-1' A, DATE '2015-04-01' VALID_FROM, DATE '9999-12-31' VALID_TO FROM dual
  3  UNION ALL
  4  SELECT 'ARN-1' A, DATE '2015-05-01' VALID_FROM, DATE '9999-12-31' VALID_TO FROM dual
  5  UNION ALL
  6  SELECT 'ARN-1' A, DATE '2015-06-01' VALID_FROM, DATE '9999-12-31' VALID_TO FROM dual
  7  UNION ALL
  8  SELECT 'ARN-1' A, DATE '2015-07-01' VALID_FROM, DATE '9999-12-31' VALID_TO FROM dual
  9  )
 10  -- end of sample_data mimicking real table
 11  SELECT a,
 12    valid_from,
 13    CASE
 14      WHEN rn = 1
 15      THEN DATE '9999-12-31'
 16      ELSE valid_to
 17    END valid_to
 18  FROM
 19    (SELECT A,
 20      valid_from,
 21      row_number() OVER(ORDER BY valid_from DESC) rn,
 22      last_day(valid_from) valid_to
 23    FROM sample_data
 24    )
 25  ORDER BY valid_from;

A     VALID_FROM  VALID_TO
----- ----------- -----------
ARN-1 01-APR-2015 30-APR-2015
ARN-1 01-MAY-2015 31-MAY-2015
ARN-1 01-JUN-2015 30-JUN-2015
ARN-1 01-JUL-2015 31-DEC-9999

SQL>

Oracle安装程序

CREATE TABLE table_name ( A, VALID_FROM, VALID_TO ) AS
SELECT 'ARN-1', DATE '2015-04-01', DATE '9999-12-31' FROM DUAL UNION ALL
SELECT 'ARN-1', DATE '2015-05-01', DATE '9999-12-31' FROM DUAL UNION ALL
SELECT 'ARN-1', DATE '2015-06-01', DATE '9999-12-31' FROM DUAL;
UPDATE table_name t
SET valid_to = ( SELECT NVL( next_valid_from, valid_to )
                 FROM   (
                   SELECT a,
                          valid_from,
                          LEAD( valid_from ) OVER ( PARTITION BY a ORDER BY valid_from )
                            - INTERVAL '1' SECOND -- Change to DAY if you prefer
                            AS next_valid_from,
                          valid_to
                   FROM   table_name
                 ) n
                 WHERE  t.a = n.a
                 AND    t.valid_from = n.valid_from
               );
SELECT * FROM table_name;

A     VALID_FROM            VALID_TO            
----- --------------------- ---------------------
ARN-1 2015-04-01 00:00:00   2015-04-30 23:59:59   
ARN-1 2015-05-01 00:00:00   2015-05-31 23:59:59   
ARN-1 2015-06-01 00:00:00   9999-12-31 00:00:00   
更新

CREATE TABLE table_name ( A, VALID_FROM, VALID_TO ) AS
SELECT 'ARN-1', DATE '2015-04-01', DATE '9999-12-31' FROM DUAL UNION ALL
SELECT 'ARN-1', DATE '2015-05-01', DATE '9999-12-31' FROM DUAL UNION ALL
SELECT 'ARN-1', DATE '2015-06-01', DATE '9999-12-31' FROM DUAL;
UPDATE table_name t
SET valid_to = ( SELECT NVL( next_valid_from, valid_to )
                 FROM   (
                   SELECT a,
                          valid_from,
                          LEAD( valid_from ) OVER ( PARTITION BY a ORDER BY valid_from )
                            - INTERVAL '1' SECOND -- Change to DAY if you prefer
                            AS next_valid_from,
                          valid_to
                   FROM   table_name
                 ) n
                 WHERE  t.a = n.a
                 AND    t.valid_from = n.valid_from
               );
SELECT * FROM table_name;

A     VALID_FROM            VALID_TO            
----- --------------------- ---------------------
ARN-1 2015-04-01 00:00:00   2015-04-30 23:59:59   
ARN-1 2015-05-01 00:00:00   2015-05-31 23:59:59   
ARN-1 2015-06-01 00:00:00   9999-12-31 00:00:00   
输出

CREATE TABLE table_name ( A, VALID_FROM, VALID_TO ) AS
SELECT 'ARN-1', DATE '2015-04-01', DATE '9999-12-31' FROM DUAL UNION ALL
SELECT 'ARN-1', DATE '2015-05-01', DATE '9999-12-31' FROM DUAL UNION ALL
SELECT 'ARN-1', DATE '2015-06-01', DATE '9999-12-31' FROM DUAL;
UPDATE table_name t
SET valid_to = ( SELECT NVL( next_valid_from, valid_to )
                 FROM   (
                   SELECT a,
                          valid_from,
                          LEAD( valid_from ) OVER ( PARTITION BY a ORDER BY valid_from )
                            - INTERVAL '1' SECOND -- Change to DAY if you prefer
                            AS next_valid_from,
                          valid_to
                   FROM   table_name
                 ) n
                 WHERE  t.a = n.a
                 AND    t.valid_from = n.valid_from
               );
SELECT * FROM table_name;

A     VALID_FROM            VALID_TO            
----- --------------------- ---------------------
ARN-1 2015-04-01 00:00:00   2015-04-30 23:59:59   
ARN-1 2015-05-01 00:00:00   2015-05-31 23:59:59   
ARN-1 2015-06-01 00:00:00   9999-12-31 00:00:00   

您还没有解释要做什么,也没有解释如何将
有效\u设置为
日期的逻辑。总是在下一次
开始前一天从
开始生效?如果间隔不是一个月(缺少一行,或者不是从1号开始),该怎么办?OP似乎希望最后一个定义的期间保留神奇的值结束日期。虽然它不是很清楚…我认为这是一个打字错误,但如果OP希望这样,那么它将需要一个窗口功能。我看到了使用滞后/超前的其他答案,但我认为最后一天更合适,只是最大有效时间应该有神奇的日期。除非记录中有差距,或者它们不总是从1号开始。但目前尚不清楚这是否可能发生,或者如果发生,产出应该是什么。如果从
开始的
有效日期是每个月的第一天,那么是的,只是不确定可以从有限的信息中安全地假定这一点*8-)是的,你是对的。就目前的问题范围而言,我已经编辑了我的答案。