根据sql server中的后续开始日期更新结束日期

时间:2017-09-25 10:03:41

标签: sql sql-server sql-server-2008

我是SQL Server的新手,我尝试了一些方法,但无法成功地使用相应产品的即时连续值(start_day-1天)更新以下空值,这是我的生产方案,所以我无法发布我试过的原始查询。所以请帮助我实现这种情况。

Table_Name - 产品

------------------------------------------
Product_cd |    Start_date |    end_date
------------------------------------------
A          |    2017-01-01 |    2017-01-10
A          |    2017-01-11 |    2017-03-09
A          |    2017-03-10 |    2099-12-31
B          |    2015-01-01 |    2017-01-10
B          |    2017-01-11 |    2099-12-31
C          |    2015-01-01 |    2015-01-10
C          |    2015-01-11 |    2015-03-09
C          |    2015-03-10 |    2015-03-09
C          |    2015-03-10 |    2099-12-31
D          |    2000-01-01 |    2000-10-21
D          |    2000-10-22 |    2000-11-12
D          |    2000-11-13 |    2015-03-09
D          |    2015-03-10 |    2099-12-31

正确的数据期望:(在end_date中为Null,相同产品的min(start_date)为1天之后)

Button_to

4 个答案:

答案 0 :(得分:1)

正如etsa所说,LEAD窗口功能是你需要在这里使用的(见here)。你只能把它放在一个SELECT中,所以你的更新需要通过像CTE这样的东西。尝试这样的事情......

DROP TABLE IF EXISTS StartEnd
CREATE TABLE StartEnd
(   Product_cd char(1),
    Startdate date,
    end_date date
)
INSERT dbo.StartEnd (Product_cd,Startdate,end_date)
VALUES 
('A','2017-01-01','2017-01-10' ),
('A','2017-01-11',null         ),
('A','2017-03-10','2099-12-31' ),
('B','2015-01-01',null         ),
('B','2017-01-11','2099-12-31' ),
('C','2015-01-01','2015-01-10' ),
('C','2015-01-11',null         ),
('C','2015-03-10','2015-03-09' ),
('C','2015-03-10','2099-12-31' ),
('D','2000-01-01','2000-10-21' ),
('D','2000-10-22','2000-11-12' ),
('D','2000-11-13',null         ),
('D','2015-03-10','2099-12-31' );

SELECT * FROM dbo.StartEnd AS se;

WITH UpdateRows AS
(
    SELECT se.Product_cd,
           se.Startdate,
           se.end_date,
           CASE WHEN se.end_date IS NULL 
                THEN dateadd(DAY,-1,lead(se.StartDate,1) OVER(PARTITION BY se.Product_cd ORDER BY se.Startdate))
                ELSE se.end_date END AS newEndDate
    FROM dbo.StartEnd AS se
)
UPDATE UpdateRows
SET end_date = newEndDate
WHERE end_date IS NULL;

SELECT * FROM dbo.StartEnd AS se;

答案 1 :(得分:0)

要提取所需的值,可以使用以下查询。它使用Windows分析函数LEAD()来查找PRODUCT_CD的下一个值,使用START_DATE排序)。 (正如戈登在MSSQL 2012中所指出的那样)

SELECT *
FROM (SELECT PRODUCT_CD, START_DATE, END_DATE
       , LEAD(START_DATE) OVER (PARTITION BY PRODUCT_CD ORDER BY START_DATE)-1  AS DATE_SUCC
      FROM PRODUCT) A 
WHERE END_DATE IS NULL AND DATE_SUCC IS NOT NULL;

尝试自行更新。如果您发现任何问题,请告诉我们,我们会一起看。

我认为尝试更新是有用的,但其他人并不这么认为。 这是更新,从我的SELECT开始(我不认为CTE是必要的)。我在BEGIN TRAN / ROLLBACK TRAN中使用它,所以你可以检查它。

BEGIN TRAN
UPDATE A SET END_DATE = A.DATE_SUCC
FROM (SELECT PRODUCT_CD, START_DATE, END_DATE
      , LEAD(START_DATE) OVER (PARTITION BY PRODUCT_CD ORDER BY START_DATE)-1  AS DATE_SUCC
      FROM PRODUCT) A 
WHERE A.END_DATE IS NULL AND A.DATE_SUCC IS NOT NULL
SELECT * FROM PRODUCT
ROLLBACK TRAN

输出样本:

PRODUCT_CD  START_DATE              END_DATE
A           2017-01-01 00:00:00.000 2017-01-10 00:00:00.000
A           2017-01-11 00:00:00.000 2017-03-09 00:00:00.000
A           2017-03-10 00:00:00.000 2099-12-31 00:00:00.000
B           2015-01-01 00:00:00.000 2017-01-10 00:00:00.000
B           2017-01-11 00:00:00.000 2099-12-31 00:00:00.000
...

答案 2 :(得分:0)

在SQL Server 2012+中,您可以使用lead()。在早期版本中,您需要另一种方法。这是一个:

update p
    set end_date = dateadd(day, -1, p2.start_date)
    from product p outer apply
         (select top 1 p2.*
          from product p2
          where p2.product_cd = p.product_cd and
                p2.start_date > p.start_date
          order by p2.start_date desc
         ) p2
     where p.end_date is null;

如果您只想检索数据,则可以在from中使用相同的select子句。

答案 3 :(得分:0)

试试这个......

public function create_db($dbname,$db_user,$db_password)
{ 
    $this->load->dbforge();
    $this->dbforge->create_database($dbname);
    $this->db->query("CREATE USER '". $db_user ."'@'localhost' IDENTIFIED BY '". $db_password ."';");
    $this->db->query("GRANT ALL PRIVILEGES  ON  ".$dbname.". * TO '". $db_user ."'@'localhost';");
    return $dbname;
}