Sol*_*rac 4 sql-server sql-server-2014
这是我有的表的一个例子:
Part No | Start Date | End Date |Cost
ABCD1 | 2014-01-01 | 2014-04-01|50.99
BDE2 | 2014-01-01 | 2014-03-01|14.59
ABCD1 | 2014-04-13 | 2014-05-01|13.99
Run Code Online (Sandbox Code Playgroud)
这是我想看到的输出
Part No | Start Date | End Date |Cost |Period
ABCD1 | 2014-01-01 | 2014-04-01|50.99 |2014/01
ABCD1 | 2014-01-01 | 2014-04-01|50.99 |2014/02
ABCD1 | 2014-01-01 | 2014-04-01|50.99 |2014/03
BDE2 | 2014-01-01 | 2014-03-01|14.59 |2014/01
BDE2 | 2014-01-01 | 2014-03-01|14.59 |2014/02
ABCD1 | 2014-04-13 | 2014-05-01|13.99 |2014/04
Run Code Online (Sandbox Code Playgroud)
我想根据日期范围添加一定数量的行。此外,在每一行中添加基本上是月份和年份的列期间。
我建议创建一个日期表并将该表交叉连接到您的零件表,如下例所示。
这样做是tempdb
为了不要踩到其他任何东西。
USE tempdb;
Run Code Online (Sandbox Code Playgroud)
创建一个Months
表,其中包含年、月和开始日期:
CREATE TABLE dbo.Months
(
iYear int NOT NULL
, iMonth int NOT NULL
, dDate date NOT NULL
, CONSTRAINT pk_Months
PRIMARY KEY CLUSTERED
(iYear, iMonth)
);
Run Code Online (Sandbox Code Playgroud)
使用 CTE 将行填充到上表中。本示例在 1900-01-01 到 2173-10-01 的范围内创建年/月:
;WITH cte AS
(
SELECT v.Num
FROM (VALUES (0), (1), (2), (3), (4), (5), (6), (7), (8), (9))v(Num)
)
, cteDates AS
(
SELECT dDate = DATEADD(DAY, 0, ROW_NUMBER() OVER (ORDER BY c1.Num))
FROM cte c1
CROSS APPLY cte c2
CROSS APPLY cte c3
CROSS APPLY cte c4
CROSS APPLY cte c5
)
, cteMonths AS
(
SELECT iYear = DATEPART(YEAR, cteDates.dDate)
, iMonth = DATEPART(MONTH, cteDates.dDate)
FROM cteDates
)
INSERT INTO dbo.Months(iYear, iMonth, dDate)
SELECT cteMonths.iYear
, cteMonths.iMonth
, DATEFROMPARTS(cteMonths.iYear, cteMonths.iMonth, 1)
FROM cteMonths
GROUP BY cteMonths.iYear
, cteMonths.iMonth
ORDER BY cteMonths.iYear
, cteMonths.iMonth;
Run Code Online (Sandbox Code Playgroud)
使用示例“零件”数据创建表:
CREATE TABLE dbo.PartCosts
(
PartNum varchar(10) NOT NULL
, StartDate date NOT NULL
, EndDate date NOT NULL
, Cost decimal(10,2) NOT NULL
);
INSERT INTO dbo.PartCosts(PartNum, StartDate, EndDate, Cost)
VALUES ('ABCD1', '2014-01-01', '2014-04-01', 50.99)
, ('BDE2', '2014-01-01', '2014-03-01', 14.59)
, ('ABCD1', '2014-04-01', '2014-05-01', 13.99);
Run Code Online (Sandbox Code Playgroud)
运行交叉连接以获得您想要的结果:
SELECT pc.PartNum
, pc.StartDate
, pc.EndDate
, pc.Cost
, Period = CONVERT(varchar(7), m.dDate, 111)
FROM dbo.PartCosts pc
CROSS JOIN dbo.Months m
WHERE pc.StartDate <= m.dDate
AND pc.EndDate > m.dDate;
Run Code Online (Sandbox Code Playgroud)
结果:
+---------+------------+------------+-------+----- ----+ | 零件编号 | 开始日期 | 结束日期 | 成本 | 期间 | +---------+------------+------------+-------+----- ----+ | ABCD1 | 2014-01-01 | 2014-04-01 | 50.99 | 2014/01 | | ABCD1 | 2014-01-01 | 2014-04-01 | 50.99 | 2014/02 | | ABCD1 | 2014-01-01 | 2014-04-01 | 50.99 | 2014/03 | | BDE2 | 2014-01-01 | 2014-03-01 | 14.59 | 2014/01 | | BDE2 | 2014-01-01 | 2014-03-01 | 14.59 | 2014/02 | | ABCD1 | 2014-04-01 | 2014-05-01 | 13.99 | 2014/04 | +---------+------------+------------+-------+----- ----+
这是另一种方法。鉴于此表:
CREATE TABLE #PartCosts
(
PartNo varchar(32) NOT NULL,
StartDate date NOT NULL,
EndDate date NOT NULL,
Cost decimal(18,2) NOT NULL
);
INSERT #PartCosts(PartNo, StartDate, EndDate, Cost)
VALUES('ABCD1','2014-01-01','2014-04-01',50.99),
('BDE2 ','2014-01-01','2014-03-01',14.59),
('ABCD1','2014-04-01','2014-05-01',13.99);
Run Code Online (Sandbox Code Playgroud)
我们只需要生成一系列等于最大月份差距的数字:
DECLARE @range int;
SELECT @range = MAX(DATEDIFF(MONTH, StartDate, EndDate)) FROM #PartCosts;
;WITH x(x) AS (SELECT 0 UNION ALL SELECT x+1 FROM x WHERE x <= (@range-1))
SELECT p.PartNo, p.StartDate, p.EndDate, p.Cost,
[Period] = CONVERT(char(7), DATEADD(MONTH, x.x, p.StartDate), 111)
FROM x CROSS JOIN #PartCosts AS p
WHERE p.EndDate > DATEADD(MONTH, x.x, p.StartDate)
ORDER BY p.StartDate, p.PartNo
OPTION (MAXRECURSION 0);
Run Code Online (Sandbox Code Playgroud)
MAXRECURSION
仅当您的范围跨越 100 个月以上时才需要该选项,但安全总比抱歉好。
归档时间: |
|
查看次数: |
6845 次 |
最近记录: |