Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Jul 6th, 2012  |  syntax: None  |  size: 3.33 KB  |  hits: 14  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. How to avoid overlapping date ranges when using a grouping clause?
  2. create table #items (
  3.       code varchar(4)
  4.     , class varchar(4)
  5.     , txdate datetime
  6. )
  7.  
  8. insert into #items (code, class, txdate) values ('A', 'C', '2010-01-01');
  9. insert into #items (code, class, txdate) values ('A', 'C', '2010-01-02');
  10. insert into #items (code, class, txdate) values ('A', 'C', '2010-01-03');
  11. insert into #items (code, class, txdate) values ('A', 'D', '2010-01-04');
  12. insert into #items (code, class, txdate) values ('A', 'D', '2010-01-05');
  13. insert into #items (code, class, txdate) values ('A', 'C', '2010-01-06');
  14. insert into #items (code, class, txdate) values ('A', 'C', '2010-01-07');
  15. insert into #items (code, class, txdate) values ('A', 'D', '2010-01-08');
  16. insert into #items (code, class, txdate) values ('A', 'D', '2010-01-09');
  17.  
  18. select code
  19. , class
  20. , min(txdate) mindate
  21. , max(txdate) maxdate
  22. from #items
  23. group by code, class
  24.        
  25. |code|class|mindate   |maxdate   |
  26. ----------------------------------
  27. |A   |C    |2010-01-01|2010-01-07|
  28. |A   |D    |2010-01-04|2010-01-09|
  29.        
  30. |code|class|mindate   |maxdate   |
  31. ----------------------------------
  32. |A   |C    |2010-01-01|2010-01-03|
  33. |A   |D    |2010-01-04|2010-01-05|
  34. |A   |C    |2010-01-06|2010-01-07|
  35. |A   |D    |2010-01-08|2010-01-09|
  36.        
  37. ;with cteNtile as (
  38.     select code, class, txdate,
  39.            ntile((select count(*) from (select NULL as dummy from #items group by code, class) a)) over(partition by code, class order by txdate) as tilenum
  40.         from #items
  41. )
  42. select code, class, MIN(txdate) as mindate, MAX(txdate) as maxdate
  43.     from cteNtile
  44.     group by code, class, tilenum
  45.     order by mindate, maxdate
  46.        
  47. ;WITH items1 AS (
  48. SELECT ROW_NUMBER() OVER (ORDER BY txdate) rowid, code, class, txdate
  49. from #items
  50. ),
  51. items2 AS (
  52. SELECT ROW_NUMBER() OVER (ORDER BY rowid) id, rowid, i1.Code, i1.Class, i1.txdate
  53. FROM items1 i1
  54. WHERE NOT EXISTS (SELECT 1 FROM items1 i2
  55.                   WHERE i2.txdate < i1.txdate
  56.                   AND i2.class = i1.class
  57.                   AND i2.Code = i1.Code
  58.                   AND i2.rowid+1=i1.rowid)
  59. )
  60. SELECT items2.code, items2.class, items2.txdate mindate, items1.txdate maxdate
  61. FROM items2,  items2 items3, items1
  62. WHERE (items2.id+1=items3.id AND items3.rowid-1=items1.rowid)
  63. OR items2.rowid = (SELECT MAX(t.rowid) FROM items1 t)
  64. UNION
  65. SELECT items2.code, items2.class, MAX(items2.txdate) mindate, MAX(items1.txdate) maxdate
  66. FROM items2, items1
  67. WHERE items1.class = items2.class
  68. GROUP BY items1.class, items2.class, items2.code, items2.class
  69. ORDER BY items2.txdate
  70.        
  71. select a.code, a.class, a.txdate as mindate, b.txdate as maxdate
  72. from (
  73.     --Find minimum island
  74.     select code
  75.         , class
  76.         , txdate
  77.         , row_number() over (order by code, class, txdate) as n
  78.     from #items tb1
  79.     where not exists (
  80.         select *
  81.         from #items tb2
  82.         where datediff(d, tb1.txdate, tb2.txdate) = -1      
  83.           and tb1.class = tb2.class
  84.           and tb1.code = tb2.code
  85.     )
  86. ) as a
  87. inner join (
  88.     --Find maximum island
  89.     select code
  90.         , class
  91.         , txdate
  92.         , row_number() over (order by code, class, txdate) as n
  93.     from #items tb1
  94.     where not exists (
  95.         select *
  96.         from #items tb2
  97.         where datediff(d, tb1.txdate, tb2.txdate) = 1  
  98.           and tb1.class = tb2.class
  99.           and tb1.code = tb2.code
  100.     )
  101. ) as b on a.n = b.n