需要从单个生效日期

时间:2016-06-24 14:29:06

标签: sql date

我正在尝试编写SQL来计算每个项目的生效日期的单个日期的开始日期和结束日期。下面是我的数据外观的概念。有些时候,项目的最后生效日期将在过去,所以我希望结束日期为今天的一年。表格示例中的其他两个项目将来都有生效日期,因此无需创建和结束今天的一年。

我尝试了几种方法,但总是遇到不好的数据。以下是我的查询和不良结果的示例

select distinct tb1.itemid,tb1.EffectiveDate as startdate
, case 
when dateadd(d,-1,tb2.EffectiveDate) < getdate() 
or tb2.EffectiveDate is  null
then getdate() +365 
else dateadd(d,-1,tb2.EffectiveDate) 
end as enddate
from #test tb1

left join #test as tb2 on (tb2.EffectiveDate > tb1.EffectiveDate 
   or tb2.effectivedate is null) and tb2.itemid = tb1.itemid

left join #test tb3 on (tb1.EffectiveDate < tb3.EffectiveDate 
  andtb3.EffectiveDate <tb2.EffectiveDate or tb2.effectivedate is null) 
  and tb1.itemid = tb3.itemid

left join #test tb4 on tb1.effectivedate = tb4.effectivedate \
  and tb1.itemid = tb4.itemid

where tb1.itemID in (62741,62740, 65350)

结果 - 还有一条额外的62740线 Bad Results

我希望在下面看到,因为前两个项目的未来结束日期不需要创建今天的结束日期+ 365但最后一个只有一个生效日期,所以我们必须计算结束日期。

4 个答案:

答案 0 :(得分:0)

我想我已经正确地阅读了你的问题。如果你能提供预期的产量,那将会有很大的帮助。

测试数据

CREATE TABLE #TestData (itemID int, EffectiveDate date)
INSERT INTO #TestData (itemID, EffectiveDate)
VALUES
(62741,'2016-06-25')
,(62741,'2016-06-04')
,(62740,'2016-07-09')
,(62740,'2016-06-25')
,(62740,'2016-06-04')
,(65350,'2016-05-28')

查询

SELECT
a.itemID
,MIN(a.EffectiveDate) StartDate
,MAX(CASE WHEN b.MaxDate > GETDATE() THEN b.MaxDate ELSE CONVERT(date,DATEADD(yy,1,GETDATE())) END) EndDate
FROM #TestData a
JOIN (SELECT itemID, MAX(EffectiveDate) MaxDate FROM #TestData GROUP BY itemID) b
ON a.itemID = b.itemID
GROUP BY a.itemID

结果

itemID  StartDate   EndDate
62740   2016-06-04  2016-07-09
62741   2016-06-04  2016-06-25
65350   2016-05-28  2017-06-24

答案 1 :(得分:0)

这应该这样做:

SELECT itemid
      ,effective_date AS "Start"
       ,(SELECT MIN(effective_date)
          FROM effective_date_tbl
         WHERE effective_date > edt.effective_date
           AND itemid = edt.itemid) AS "End"
  FROM effective_date_tbl edt
 WHERE effective_date <
       (SELECT MAX(effective_date) FROM effective_date_tbl WHERE itemid = edt.itemid)
 UNION ALL
 SELECT itemid
       ,effective_date AS "Start"
       ,(SYSDATE + 365) AS "End"
 FROM effective_date_tbl edt
 WHERE 1 =  ( SELECT COUNT(*) FROM effective_date_table WHERE itemid = edt.itemid )      
 ORDER BY 1, 2, 3;

答案 2 :(得分:0)

我为表格中有多个EffectiveDate的项目进行了此练习

您可以创建此视图

CREATE view [VW_TESTDATA] 
AS ( SELECT * FROM  
    (SELECT ROW_NUMBER() OVER (ORDER BY Item,CONVERT(datetime,EffectiveDate,110)) AS ID, Item, DATA
FROM MyTable ) AS Q
)

所以使用select来比较同一个项目

select * from [VW_TESTDATA] as A inner join [VW_TESTDATA] as B on A.Item = B.Item and A.id = B.id-1

通过这种方式你总是次要的和主要的日期

我不明白如何处理只有一个Item的日期,但这似乎是最简单的事情,并且可以使用UNION ALL添加到此查询中,因为视图不包含单个项目

您还需要弄清楚如何使用两个相等的EffectiveDate来处理Item

答案 3 :(得分:-1)

你应该在陈述时使用案例。
[错误的查询,因为对要求的误解]

SELECT 
       ItemID AS Item,
       StartDate,
       CASE WHEN EndDate < Sysdate THEN Sysdate + 365 ELSE EndDate END AS EndDate 
FROM 
(
  SELECT tabStartDate.ItemID, tabStartDate.EffectiveDate AS StartDate, tabEndDate.EffectiveDate AS EndDate
  FROM TableItems tabStartDate
  JOIN TableItems tabEndDate on tabStartDate.ItemID = tabEndDate.ItemID 
) TableDatesPerItem
WHERE StartDate < EndDate



在OP和一些评论 中作出澄清后, 更新

我发现一个非常便携的解决方案,因为它没有使用分区,而是赞同一种索引规则,使得每个项目的日期与具有相同id的其他日期相对应,按时间顺序排列。

可移植性显然与查询的“困难”部分有关,而行编号机制和转换也有所改进,但我认为这不是问题。

我为MySql发了一个版本,它可以试试SQL Fiddle ..

  

表格

CREATE TABLE ITEMS 
      (`ItemID` int, `EffectiveDate` Date);

INSERT INTO ITEMS
      (`ItemID`, `EffectiveDate`)
VALUES
  (62741, DATE(20160625)),
  (62741, DATE(20160604)),
  (62740, DATE(20160709)),
  (62740, DATE(20160625)),
  (62740, DATE(20160604)),
  (62750, DATE(20160528))
;
  

<强>查询

SELECT 
     RESULT.ItemID AS ItemID, 
     DATE_FORMAT(RESULT.StartDate,'%m/%d/%Y') AS StartDate, 
     CASE WHEN RESULT.EndDate < CURRENT_DATE
      THEN DATE_FORMAT((CURRENT_DATE + INTERVAL 365 DAY),'%m/%d/%Y') 
      ELSE DATE_FORMAT(RESULT.EndDate,'%m/%d/%Y') 
     END AS EndDate
FROM
(
   SELECT 
     tabStartDate.ItemID AS ItemID, 
     tabStartDate.StartDate AS StartDate, 
     tabEndDate.EndDate
     ,tabStartDate.IDX,
     tabEndDate.IDX AS IDX2
     FROM
     (
      SELECT 
         tabStartDateIDX.ItemID AS ItemID, 
         tabStartDateIDX.EffectiveDate AS StartDate,
         @rownum:=@rownum+1 AS IDX
      FROM ITEMS AS tabStartDateIDX
      ORDER BY tabStartDateIDX.ItemID,  tabStartDateIDX.EffectiveDate
     )AS tabStartDate 
     JOIN
     (
       SELECT 
         tabEndDateIDX.ItemID AS ItemID, 
         tabEndDateIDX.EffectiveDate AS EndDate,
         @rownum:=@rownum+1 AS IDX
       FROM ITEMS AS tabEndDateIDX 
       ORDER BY tabEndDateIDX.ItemID, tabEndDateIDX.EffectiveDate
      )AS tabEndDate
      ON tabStartDate.ItemID = tabEndDate.ItemID AND (tabEndDate.IDX - tabStartDate.IDX = ((select count(*) from ITEMS)+1) )
     ,(SELECT @rownum:=0) r
  UNION
  (
    SELECT 
       tabStartDateSingleItem.ItemID AS ItemID, 
       tabStartDateSingleItem.EffectiveDate AS StartDate,
       tabStartDateSingleItem.EffectiveDate AS EndDate
       ,0 AS IDX,0 AS IDX2
     FROM ITEMS AS tabStartDateSingleItem
    Group By tabStartDateSingleItem.ItemID
    HAVING  Count(tabStartDateSingleItem.ItemID) = 1
  )
) AS RESULT
;