我是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
答案 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;
}