Home > Back-end >  How to extrapolate dates in SQL Server to calculate the daily counts?
How to extrapolate dates in SQL Server to calculate the daily counts?

Time:11-24

This is how the data looks like. It's a long table

enter image description here

I need to calculate the number of people employed by day

enter image description here

How to write SQL Server logic to get this result? I treid to create a DATES table and then join, but this caused an error because the table is too big. Do I need a recursive logic?

CodePudding user response:

Try limiting the scope of your date table. In this example I have a table of dates named TallyStickDT.

SELECT dt, COUNT(name) FROM 
(SELECT dt FROM tallystickdt WHERE dt >= (SELECT MIN(hired) FROM #employees) AND dt <= GETDATE()) A
 LEFT OUTER JOIN #employees E ON A.dt >= E.Hired AND A.dt <= e.retired
GROUP BY dt
ORDER BY dt

CodePudding user response:

For future questions, don't post images of data. Instead, use a service like dbfiddle. I'll anyhow add a sketch for an answer, with a better-prepared question you could have gotten a complete answer. Anyhow here it goes:

-- extrema is the least and the greatest date in staff table
with extrema(mn, mx) as (
    select least(min(hired),min(retired)) as mn
         , greatest(max(hired),max(retired)) as mx
    from staff
), calendar (dt) as (
    -- we construct a calendar with every date between extreme values
    select mn from extrema
    union all
    select dateadd(day, 1, d)
    from calendar
    where dt < (select mx from extrema)
)
-- finally we can count the number of employed people for each such date
select dt, count(1) 
from calendar c 
join staff s
    on c.dt between s.hired and s.retired
group by dt; 

If you find yourself doing this kind of calculation often, it is a good idea to create a calendar table. You can add other attributes to it such as if it is a day of in the middle of the week etc.

With a constraint as:

CHECK(hired <= retired)

the first part can be simplified to:

with extrema(mn, mx) as (
    select min(hired) as mn
         , max(retired) as mx
    from staff
),

CodePudding user response:

Assuming Current Employees have a NULL retirement date

Declare @Date1 date = '2015-01-01'
Declare @Date2 date = getdate()

Select A.Date
      ,HeadCount = count(B.name)
 From ( Select Top (DateDiff(DAY,@Date1,@Date2) 1) 
               Date=DateAdd(DAY,-1 Row_Number() Over (Order By (Select Null)),@Date1) 
         From  master..spt_values n1,master..spt_values n2
      ) A
 Left Join YourTable B on A.Date >= B.Hired and A.Date <= coalesce(B.Retired,getdate())
 Group BY A.Date

CodePudding user response:

You need a calendar table for this. You start with the calendar, and LEFT JOIN everything else, using BETWEEN logic.

You can use a real table. Or you can generate it on the fly, like this:

WITH
    L0 AS ( SELECT c = 1
            FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
                        (1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
    L1 AS ( SELECT c = 1 FROM L0 A, L0 B, L0 C, L0 D ),
    Nums AS ( SELECT rownum = ROW_NUMBER() OVER(ORDER BY (SELECT 1))
              FROM L1 ),
    Dates AS (
      SELECT TOP (DATEDIFF(day, '20141231', GETDATE()))
        Date = DATEADD(day, rownum, '20141231')
      FROM Nums
    )

SELECT
  d.Date,
  NumEmployed = COUNT(*)
FROM Dates d
JOIN YourTable t ON d.Date BETWEEN t.Hired AND t.Retired
GROUP BY
  d.Date;

If your dates have a time component then you need to use >= AND < logic

  • Related