如何在条件中复制sql中的数据

时间:2016-12-05 22:04:55

标签: sql sql-server database

我有一张桌子作为table_A。 table_A包括这些列

-CountryName
-Min_Date
-Max_Date
-Number

我希望按月分开复制数据。例如

Argentina | 2015-01-04 | 2015-04-07 | 100
England   | 2015-02-08 | 2015-03-11 | 90

我希望看到一张表(每月分隔)

Argentina | 01-2015 | 27 //(days to end of the min_date's month)
Argentina | 02-2015 | 29 //(days full month)
Argentina | 03-2015 | 31 //(days full month)
Argentina | 04-2015 | 7  //(days from start of the max_date's month)
England   | 02-2015 | 21 //(days)
England   | 03-2015 | 11 //(days)

我为每条记录做了太多尝试。但现在我的大脑太混乱了,我的项目正在推迟。

有谁知道我该如何解决这个问题。我尝试使用datediff计数复制每一行,但它不起作用

WITH cte AS (
    SELECT CountryName, ISNULL(DATEDIFF(M,Min_Date ,Max_Date )+1,1) as count FROM table_A
    UNION ALL
    SELECT CountryName, count-1 FROM cte WHERE count>1
)
SELECT CountryName,count FROM cte

3 个答案:

答案 0 :(得分:1)

- 生成每个国家/地区的最短和最长日期之间的所有日期。

- 然后获取每个国家/地区,年,月的月份开始日期和月份结束日期。

- 最后得到月初和月末的日期差异。

WITH cte AS (
    SELECT Country, min_date dt,min_date,max_date FROM t
    UNION ALL
    SELECT Country, dateadd(dd,1,dt),min_date,max_date FROM cte WHERE  dt < max_date
)
,monthends as (
SELECT country,year(dt) yr,month(dt) mth,max(dt) monthend,min(dt) monthstart
FROM cte
GROUP BY country,year(dt),month(dt)) 
select country
,cast(mth as varchar(2))+'-'+cast(yr as varchar(4)) yr_month
,datediff(dd,monthstart,monthend)+1 days_diff
from monthends

<强> Sample Demo

编辑:另一种选择是生成所有日期一次(此处显示的示例生成从2000年到2050年的51年日期),然后将其加入表格以逐月获取日期。

WITH cte AS (
    SELECT cast('2000-01-01' as date) dt,cast('2050-12-31' as date) maxdt
    UNION ALL
    SELECT dateadd(dd,1,dt),maxdt FROM cte WHERE  dt < maxdt
)    
SELECT country,year(dt) yr,month(dt) mth, datediff(dd,min(dt),max(dt))+1 days_diff
FROM cte c
JOIN t on c.dt BETWEEN t.min_date and t.max_date
GROUP BY country,year(dt),month(dt)
OPTION (MAXRECURSION 0)

答案 1 :(得分:0)

我认为你有正确的想法。但是你需要构建月份:

WITH cte AS (
      SELECT CountryName, Min_Date as dte, Min_Date, Max_Date
      FROM table_A
      UNION ALL
      SELECT CountryName, DATEADD(month, 1, dte), Min_Date, Max_Date
      FROM cte
      WHERE dte < Max_date
     )
SELECT CountryName, dte
FROM cte;

获取当月的天数有点复杂。这需要一些思考。

哦,我忘记了EOMONTH()

select countryName, dte,
       (case when dte = min_date
             then datediff(day, min_date, eomonth(dte)) + 1
             when dte = max_date
             then day(dte)
             else day(eomonth(dte))
        end) as days
from cte;

答案 2 :(得分:0)

使用日历表可以让这些东西变得非常简单。 RexTester:http://rextester.com/EBTIMG23993

begin
create table #enderaric (
  CountryName varchar(16)
  , Min_Date date
  , Max_Date date
  , Number int 
  ) 
insert into #enderaric values  
  ('Argentina' ,'2015-01-04' ,'2015-04-07' ,'100') 
, ('England' ,'2015-02-08' ,'2015-03-11' ,'90') 
end;
-- select * from #enderaric
--*/"
declare @FromDate date; 
declare @ThruDate date; 
set @FromDate = '2015-01-01';
set @ThruDate = '2015-12-31';
with x as (
  select top (cast(sqrt(datediff(day, @FromDate, @ThruDate)) as int) + 1)
      [number] 
    from [master]..spt_values v
  )
/* Date Range CTE */
,cal as (
  select top (1+datediff(day, @FromDate, @ThruDate))
        DateValue  = convert(date,dateadd(day,
          row_number() over (order by x.number)-1,@FromDate)
          )

    from x cross join x as y
      order by DateValue
  )

  select 
      e.CountryName
    , YearMonth = convert(char(7),left(convert(varchar(10),DateValue),7))
    , [Days]=count(c.DateValue)
    from #enderaric as e
      inner join cal c on c.DateValue >= e.min_date 
                      and c.DateValue <=  e.max_date
    group by
        e.CountryName
      , e.Min_Date
      , e.Max_Date
      , e.Number
      , convert(char(7),left(convert(varchar(10),DateValue),7)) 

结果:

CountryName      YearMonth Days
---------------- --------- -----------
Argentina        2015-01   28
Argentina        2015-02   28
Argentina        2015-03   31
Argentina        2015-04   7
England          2015-02   21
England          2015-03   11

有关日历表的更多信息: