在由两列定义的范围内为每个月显示一行

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)

我想根据日期范围添加一定数量的行。此外,在每一行中添加基本上是月份和年份的列期间。

Han*_*non 7

我建议创建一个日期表并将该表交叉连接到您的零件表,如下例所示。

这样做是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 |
+---------+------------+------------+-------+----- ----+

  • @Bijujose 哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇哇所以 那是从地理城市迁移过来的吗? (4认同)
  • 护目镜,他们什么都不做! (2认同)

Aar*_*and 5

这是另一种方法。鉴于此表:

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 个月以上时才需要该选项,但安全总比抱歉好。