Objective: Create Staff Turnover Report from scratch - sql

I have a requirement to create staff turnover report that should display following information according to parameterized period:
current staff
starters
leavers
manager
contracted site
Currently, I have a few ideas how to get a report. Either create slowly changing dimension or copy snapshots of employees table for each period or track starter and leavers seperately for each payrun. I have tried slowly changing dimension and it did fine job on new starters; however, it failed on leavers. I am not sure if tracking starters and leaver for each payruns would work.
Created a table below as a start of solution
I am relatively new in MS SQL 2008 business. Please adise. The main goal is to identify managers and contracted sites with highest staff turnover.
Notes
-Currently, I am not using any specific techonlogy and looking for solution.
-I do intend to build and design a brand new database for the sake of the report. By database I mean a few collection of tables that sit on CRM database (SQL 2008). By Collection of tables I mean "dimension" table for managers, "dimension" table of contracted sites, and a table of staff. So currently, I think that my solution should have at least 3 tables; however, my skills are not that good to solve the puzzle.
I think that have tables above would let me to write a SQL query that could compare different periods and get required results.
payno depcod Idd Imported
12568 EDE322001 12568EDE322001A 31 December 2011
12568 EDE322001 12568EDE322001B 31 December 2011
16822 EDE322001 16822EDE322001A 31 December 2011
17694 EDE322001 17694EDE322001A 31 December 2011
12568 EDE322001 12568EDE322001A 04 January 2012
12568 EDE322001 12568EDE322001B 04 January 2012
16822 EDE322001 16822EDE322001A 04 January 2012
17694 EDE322001 17694EDE322001A 04 January 2012
12568 EDE322001 12568EDE322001A 31 January 2012
12568 EDE322001 12568EDE322001B 31 January 2012
16822 EDE322001 16822EDE322001A 31 January 2012
17694 EDE322001 17694EDE322001A 31 January 2012
17661 EDE322001 17661EDE322001A 31 January 2012
12568 EDE322001 12568EDE322001A 01 February 2012
12568 EDE322001 12568EDE322001B 01 February 2012
16822 EDE322001 16822EDE322001A 01 February 2012
17906 EDE322001 17906EDE322001A 01 February 2012
17907 EDE322001 17907EDE322001A 01 February 2012
12568 EDE322001 12568EDE322001A 29 February 2012
12568 EDE322001 12568EDE322001B 29 February 2012
17907 EDE322001 17907EDE322001A 29 February 2012
Table above is table of snapshots. Snapshot date is displayed in Imported Column. ( Applogoes for messy table; I could not figure out how to make a table) Now i need to find a away how to compare one date to another (ideally in the loop) to figure out the difference between 1st date and following date.
For instance, 17661 EDE322001 17661EDE322001A 31 January 2012 is a new staff and 16822 EDE322001 16822EDE322001A 01 February 2012 is a leaver.
Many thanks

I may be looking at this too simplistically given all the talk about slowly changing dimensions, etc, but what's wrong with a plain old bit of SQL? I'm going to assume you have an Employee table with Manager, ContractedSite, StartDate and EndDate fields.
You want the following:
Current staff. Is this current at the start of the period or at the end of the period or active at some time during the period?
Starters. People who have a StartDate greater than or equal to the start of the period but less than or equal to the end of the period.
Leavers. People who have an EndDate greater than or equal to the start of the period but less than or equal to the end of the period.
Turnover. Which brings us back to what you mean by "Current staff". Turnover is essentially the difference between the current staff at the start of the period and the current staff at the end of the period, expressed either as a raw number or a percentage. So current staff at the start of the period are people with a StartDate less than the period start and either no EndDate or an EndDate greater than or equal to the start of the period. Similarly with the current staff at the end of the period.
So you have some specific cases to extract from your data:
SELECT Manager, ContractedSite,
SUM(CASE WHEN StartDate < #PeriodStart AND ((EndDate IS NULL) OR (EndDate >= #PeriodStart)) THEN 1 END) AS OpeningStaff,
SUM(CASE WHEN StartDate >= #PeriodStart AND StartDate <= #PeriodEnd THEN 1 END) AS Starters,
SUM(CASE WHEN EndDate >= #PeriodStart AND EndDate <= #PeriodEnd) THEN 1 END) AS Leavers,
SUM(CASE WHEN StartDate <= #PeriodEnd AND ((EndDate IS NULL) OR (EndDate > #PeriodEnd)) THEN 1 END) AS ClosingStaff
FROM Employee
WHERE (StartDate <= #PeriodEnd) AND ((EndDate IS NULL) OR (EndDate >= #PeriodStart))
GROUP BY Manager, ContractedSite
ORDER BY Manager, ContractedSite
Now you just need to calculate the difference between OpeningStaff and ClosingStaff in your report to get the turnover and you're done.

Related

Sorting Month And Year Results In Microsoft Access

I have the following table in Microsoft Access
TransactionDate
Market
Details
Opening
Closing
Size
Profit/Loss
I want to run a query that shows the Profit/Loss for each month.
I have been able get a query that returns the information in the following format
TransactionDate By Month Sum Of Sum Of Profit/Loss
April 2014 €1,084.99
April 2015 €674.33
April 2016 €2,057.30
August 2014 €237.59
August 2015 -€267.82
December 2014 €375.88
December 2015 -€1,161.97
February 2015 -€603.87
February 2016 -€124.71
January 2015 €75.11
January 2016 -€1,044.35
But what I want now is for it to display in chronological order as oppose to Alphabetical order.
For example
January 2014
February 2014
March 2014
etc.
I will consider that your TransactionDate field is defined as String
If you want to order by this text field in Access, you will have to use DateValue() function.
That would give:
SELECT TransactionDate FROM yourTable ORDER BY DateValue(TransactionDate)
If your field is already formatted as a Date field, then simply use order by TransactionDate to make it work.

SQL to separate YYYY MM to fiscal year

I have a column which states month and year YYYY MM. I've separated those into two columns (Year and Month). The problem is, the year is the calendar year whereas ideally I need the fiscal year I use (Apr 01 to Mar 31 - This will never change).
Other solutions I've seen are based on date format, whereas my original column is string.
I need a statement that returns the fiscal year for my new year column instead of the calendar year.
My current statement is:
Select Month,
parsename(replace(Month,' ','.'),1) as MonthM,
parsename(replace(Month,' ','.'),2) as Year
FROM TblTrade
Which works to separate the columns.
So expected results would be for example:
Feb 15 becomes Feb and 2015.
Apr 15 becomes Apr and 2016.
Please advise.
Sql server:
declare #date datetime = getdate();
select
(YEAR(DATEADD(Month,-((DATEPART(Month,#date)+5) %12),#date))) AS Financial_Year
Assuming April is month 1
Try this
select case
when to_char(to_date(column_name,'yyyy mm'),'mm') between 01 and 03
then to_char(trunc(to_date(column_name,'yyyy mm')),'yyyy')-1
else to_number(to_char(trunc(to_date(column_name,'yyyy mm')),'yyyy')) end
fiscal_year
from table_name
I'm using oracle db
This will work when column is string and has valid data i.e date in format like yyyy mm
Since you've read those other articles (you should really mention what research you've done in your question) and you're still having problems, I've had a play for you.
If I understand correctly, you have a varchar with YYYY MM eg
2015 01
2015 02
2015 03
2015 04
etc And you want
Jan 2014
Feb 2014
Mar 2014
Apr 2015
Here goes...
Setup some test data
DROP TABLE IF EXISTS #Test;
WITH Dates AS (
SELECT CAST(GETDATE() AS DATE) AS Date
UNION ALL
SELECT DATEADD(MONTH, -1, Date) FROM Dates
WHERE Date > '20140101'
)
SELECT DISTINCT
CONVERT(VARCHAR(4), YEAR(Date)) + ' ' +RIGHT(CONVERT(VARCHAR(6), Date, 112), 2) YearMonth
INTO #Test
FROM Dates
OPTION (MAXRECURSION 0);
SELECT * FROM #Test
YearMonth
---------
2013 12
2014 01
2014 02
2014 03
2014 04
2014 05
etc
Find Fiscal Year
SELECT
LEFT(YEARMONTH, 4) Year
,RIGHT(YEARMONTH, 2) Month
,LEFT(DATENAME(MONTH , DateAdd( month , CONVERT(INT,RIGHT(YEARMONTH, 2)) , -1 )), 3) MonthName
,IIF(CONVERT(INT, RIGHT(YEARMONTH, 2)) >= 4, CONVERT(INT,LEFT(YEARMONTH, 4)), CONVERT(INT,LEFT(YEARMONTH, 4)-1 )) FiscalYear
FROM #TEST
Year Month MonthName FiscalYear
---- ----- --------- -----------
2013 12 Dec 2013
2014 01 Jan 2013
2014 02 Feb 2013
2014 03 Mar 2013
2014 04 Apr 2014
2014 05 May 2014
2014 06 Jun 2014
etc
You could put the year/month parsing in a sub query just to make the code cleaner and some of the nasty formatting could be replaced with FORMAT since you're on 2012.
Hope this is what you're after and helps.
Since you included the Tableau tag, I'll describe the Tableau approach -- which is a little different than the other answers since you tend to specify what you want to Tableau, and let its driver generate the necessary SQL for your database.
First, it will work best if you have a single field that has datatype DATE instead of separate fields for month and year.
You can then roll up dates to the nearest year, month, day etc (actually truncating to the beginning of the period) or extract specific parts of dates year, month, day etc as needed for grouping/display.
The added benefit of working with a true DATE datatype is that you can tell Tableau the beginning of your fiscal year for each data source, and it will sort dates appropriately. Just right click on a data source and set the date properties. You can also set the start of the week and the date format.

SQL Server 2012: How to order by year then month in chronological order

I have a simple query that averages numbers and breaks them down by year and month. The problem I am having is I can't find a way to order the results by year then month....in chronological order. Here is an example of my results;
Month Year AverageAmount
---------------------------------
April 2012 167582.1139
August 2012 206124.9323
December 2012 192481.8604
February 2012 227612.0485
January 2012 214315.2187
July 2012 195320.075
June 2012 196174.3195
March 2012 201199.9894
May 2012 190526.0571
November 2012 203441.5135
October 2012 216467.7777
September 2012 217635.9174
April 2013 206730.5333
August 2013 197296.0563
As you can see in the table above, the months are in alphabetical order... what I need is the results to be in chronological order, ie...
Month Year AverageAmount
----------------------------------
January 2012 214315.2187
February 2012 227612.0485
March 2012 201199.9894
April 2012 167582.1139
May 2012 190526.0571
June 2012 196174.3195
April 2012 206730.5333
July 2012 195320.075
August 2012 206124.9323
September 2012 217635.9174
October 2012 216467.7777
November 2012 203441.5135
December 2012 192481.8604
January 2013 187268.3027
February 2013 179755.0666
March 2013 200131.6533
Query:
SELECT
datename(month, col1) Month,
year(col2) Year,
avg(col3) AverageAmount
FROM
myDB
GROUP BY
datename(month, datefunded), year(datefunded)
ORDER BY
year(datefunded), datename(month, datefunded)
Any help would be greatly appreciated
Just use this ORDER BY:
ORDER BY
YEAR(datefunded), MONTH(datefunded)
That'll sort your data by the numerical values of year and month of that datefunded
Have a look at this answer: Convert month name to month number in SQL Server
Maybe that solves the sorting for you? You can use one of the suggestions to convert the month to a number, so that e.g. March > 3. Then you sort by that.

MS Access 2010: combining consecutive date ranges

At work, I've been designing an MS Access query to manipulate client service agreements.
The requirement I'm stuck on is that if a client has had multiple consecutive agreements (i.e. the start date of one is the day after the end date of the previous one), they're counted as one (so the earliest start date is used).
The relevant fields in the table are:
Agr_ID (Agreement ID), number
Per_ID (Person ID), text
Agr_Type (Agreement Type), text
Start_Date, date
End_Date, date
For example:
103, A1234, Homecare, 20th Oct 2013, 05th Nov 2013
110, A1234, OT Equip, 06th Nov 2013, 09th Dec 2013
114, A1234, Homecare, 10th Dec 2013, 19th Jan 2014
125, A1234, Homecare, 20th Jan 2014, 15th Jun 2014
147, A1234, Homecare, 16th Jun 2014, null
The last three would be considered a single agreement (spanning the date range 10th Dec 2013 to present) but the top two wouldn't (103 isn't consecutive with 114, 110 is of a different type). The latest agreement is to be used as the base, as subsequent queries will only keep those combined agreements whose end date is later than [Prompt] and which have been open for at least 365 days. So unfortunately, grabbing min(Start_Date) won't do.
So the desired result for that extract would be:
103, A1234, Homecare, 20th Oct 2013, 05th Nov 2013
110, A1234, OT Equip, 06th Nov 2013, 09th Dec 2013
147, A1234, Homecare, 10th Dec 2013, null
I'm thinking several derived tables / subqueries may be needed, to list the agreements for each client, then iteratively work backwards through the resulting table to find the earliest qualifying start date. The only consolation to the amount of recursion involved is that the table I'm basing the query on was created via a MakeTable query that filtered the raw Agreements table, so only agreements with an end date greater than [Prompt] - 365 days or null are included, and the Agreements table this is running off is under 10,000 records.

MS Access grouping query spanning start and end dates

I would like to get a running tally of how many widgets were/are rented at any one time, by month, by year. Data is held in an MS Access 2003 db;
Table name: rent_table
Fields:
rentid
startdate
enddate
rentfee
rentcost
bookingfee
Something like; Count number of rentid's that fall between month/year, then group them?
e.g. if a widget was rented from 5th Jan 2014 to 8th April 2014 it would appear as a count in Jan, Feb, Mar and April tally's.
Many thanks.
EDIT
More details (sorry);
Access db is fronted by classic ASP.
If possible I don't want to create any new tables.
No input is required in order to run the report.
There are around 350-400 widgets that could be rented at any one time.
Each widget is rented exclusively.
Report output example;
Month | Year | NumRented
Jan 2014 86
Feb 2014 113
...
Can a query pick up dates within dates? So literally do a count of the table where date >Dec 31st 2013 AND <1st Feb 2014 (to grab a count for all of January 2014) and would that include the example of the rent starting on the 5th Jan? So I could just do twelve counts for each year?
create a calendar table, e.g.
table = cal_yyyymm with one column dt_yyyymm as numeric field
populate the table with ... say 5 or 10 years of data
201401 201402 201403 ... 60 or 120 rows, a small table
make a sql
Select
dt_yyyymm,
count(*) as cnt
From cal_yyyymm
Left Join rent_table
On format(startdate,"yyyymm") >= dt_yyyymm
And dt_yyyymm >= format(enddate,"yyyymm")
think about the complications in the data -- --
widget was rented from 5th Jan 2014 to 8th Jan 2014
and again rented from 11th Jan 2014 to 21st Jan 2014
does this count at 1 or 2 in the month?
if it is 1, then the sql gets more complicated because
the rent_table first needs to have its dates converted
to yyyymm format, and second needs to be de-duped on rentid,
and third then joined to cal_ On the dates...