我在其中一个表中有此数据:
YEAR MONTH Cost
-------------------------
2018 1 25000
2018 2 32000
2018 3 9865
例如,如果Month = 1,那么我想重复行,那么我希望该行重复31次;如果Month = 2,那么我希望重复28次(实际上是根据每月的天数)
我该怎么做?
非常感谢您
答案 0 :(得分:1)
使用日历表,它将为您解决此问题以及将来的许多日期问题。
此解决方案生成具有递归CTE的解决方案。
DECLARE @StartDate DATE = '2018-01-01'
DECLARE @EndDate DATE = '2020-01-01'
;WITH GeneratedCalendar AS
(
SELECT
GeneratedDate = @StartDate,
Month = MONTH(@StartDate),
Year = YEAR(@StartDate)
UNION ALL
SELECT
GeneratedDate = DATEADD(DAY, 1, G.GeneratedDate),
Month = MONTH(DATEADD(DAY, 1, G.GeneratedDate)),
Year = YEAR(DATEADD(DAY, 1, G.GeneratedDate))
FROM
GeneratedCalendar AS G
WHERE
G.GeneratedDate < @EndDate
)
SELECT
T.YEAR,
T.MONTH,
T.Cost,
G.GeneratedDate
FROM
YourTable AS T
INNER JOIN GeneratedCalendar AS G ON
T.YEAR = G.Year AND
T.MONTH = G.Month
ORDER BY
T.YEAR,
T.MONTH
OPTION
(MAXRECURSION 30000)
答案 1 :(得分:0)
您可以使用递归CTE:
with cte as (
select year, month, datefromparts(year, month, 1) as dte, cost
from t
union all
select year, month, dateadd(day, 1, dte), cost
from t
where day(dateadd(day, 1, dte)) <> 1
)
select *
from cte;
这包括每一行的日期。
答案 2 :(得分:0)
您应该有一个日历表,您可以在其中插入表,也可以使用数字表/计数表建立一个日历表。
在这里 an excellent article 可以了解这个概念。
下面展示了一种实现此目的的方法-
select year, month,date=t.d cost from
your table cross apply(
select
d=dateadd(d,r ,cast(cast(month as varchar(2))+ '-01-'+cast(year as varchar(4)) as date))
from
(
select top 31
r=row_number() over( order by (select null))-1
from
sys.objects s1 cross join sys.objects s2)t
where month(dateadd(d,r ,cast(cast(month as varchar(2))+ '-01-'+cast(year as varchar(4)) as date)))=month
)t
答案 3 :(得分:0)
这通过CROSS APPLY使用内联表值函数:
create function YearsMonths(@year int, @month int)
returns table
as
return
Select @year [Year], @month [Month]
from master.dbo.spt_values t2
where t2.type = 'P' AND t2.number < CASE WHEN @month IN (1, 3, 5, 7, 8, 10, 12) THEN 31
WHEN @month IN (4, 6, 9, 11) THEN 30
ELSE CASE WHEN (YEAR(@year) % 4 = 0 AND
YEAR(@year) % 100 != 0) OR
(YEAR(@year) % 400 = 0)
THEN 29
ELSE 28
END
END
GO
create table yearmonthcost ([Year] int, [Month] int, [Cost] int)
insert into yearmonthcost values
(2018, 1, 25000)
, (2018, 2, 32000)
, (2018, 3, 9865)
select *
from yearmonthcost ymc
cross apply dbo.YearsMonths(ymc.[Year], ymc.[Month])
答案 4 :(得分:0)
递归CTE是您的朋友吗 假设您的表名是 T2
with A as (
select T.[year], T.[month], datefromparts(T.[year], T.[month], 1) AS D, T.[cost]
from T2 T
union all
select T.[year], T.[month], dateadd(day, 1, A.D) AS D, T.[cost]
from T2 T INNER JOIN A ON T.[year]=A.[year] AND T.[month]=A.[month] AND T.[cost]=A.[cost]
where MONTH(dateadd(day, 1, A.D)) = MONTH(A.D)
)
SELECT * FROM A
ORDER BY A.[year], A.[month], A.D
答案 5 :(得分:0)
还有一个:
DECLARE @tbl TABLE(y INT, m INT, Cost INT)
INSERT INTO @tbl VALUES
(2018,1,25000)
,(2018,2,32000)
,(2018,3,9865);
-提示CTE会立即生成31个运行编号
-此CTE与TOP
一起使用,并具有计算出的计数来检索数字的拟合计数
WITH Tally AS(SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
,(11),(12),(13),(14),(15),(16),(17),(18),(19),(20)
,(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31)) t(nr))
SELECT *
FROM @tbl t
CROSS APPLY(SELECT CONVERT(DATETIME,CONCAT(t.y,REPLACE(STR(t.m,2),' ','0'),'01'),126)) D(FirstOfMonth)
CROSS APPLY(SELECT TOP (DAY(DATEADD(MONTH,1,D.FirstOfMonth)-1)) nr FROM Tally ORDER BY nr) AS multiplier;
第一个交叉应用将计算您月份的第一天(“ 20180101”),而TOP
中的计算将添加一个月并返回一天。这是该月的最后一天。
您未指定SQL-Serer版本。这将是much easier with EOMONTH
(v2012+)和DATEFROMPARTS
(v2012+)
在v2012 +上尝试
WITH Tally AS(SELECT * FROM (VALUES(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
,(11),(12),(13),(14),(15),(16),(17),(18),(19),(20)
,(21),(22),(23),(24),(25),(26),(27),(28),(29),(30),(31)) t(nr))
SELECT *
FROM @tbl t
CROSS APPLY(SELECT TOP (DAY(EOMONTH(DATEFROMPARTS(t.y,t.m,1)))) nr FROM Tally ORDER BY nr) AS multiplier