To populate all dates in a month in SQL and SSRS - sql

We need to create a report based on employee, say Kumar, logged 3 hours.
For example,
if a person is logged Hours in system for 1-1-2021. But he didn't log for 2-1-2021.
We have a join query to get the date and worked hours for each employee.
Our present report is like below (this is the screenshot from SSRS report)
But we need the missing dates also in the report. Abhishek has logged only from 4th Jan in the system. But we need rows above 4th Jan also in the report.
First name and last name should be in those columns in the new row. The hours worked should be 0 and other column values should be N/A or Null.
But here we need a query to get all dates in a month in the report whether the employee logged hours or not.() for not logged days)
This is the report that we want in SSRS.(i created this in excel)
How can i do that?
enter image description here

You are not able to force the missing dates with SSRS. To make this work correctly, you'll need to update your query to get all the dates in your date range and then LEFT JOIN your current data to the dates.
Add a INTO to your current report query put to put the data in a #TEMP_TABLE.
SELECT <CURRENT FIELDS>
INTO #TEMP_TABLE
FROM BLAH BLAH BLAH
Then Create a table of dates for your date range using a CTE with RECURSION.
DECLARE #START_DATE DATE = '01/01/2020' --THESE DATES SHOULD BE CHANGE TO USE PARAMETERS OF YOUR DATE RANGE
DECLARE #END_DATE DATE = '03/31/2021' --OR MIN/MAX FROM THE #TEMP_TABLE
;WITH GETDATES AS
(
SELECT #START_DATE AS THEDATE
UNION ALL
SELECT DATEADD(DAY,1, THEDATE) FROM GETDATES
WHERE THEDATE < #END_DATE
)
SELECT D.THEDATE, T.*
FROM GETDATES D
LEFT JOIN #TEMP_TABLE T ON D.THEDATE = T.DATE_WORKED
OPTION (maxrecursion 0)
This will return every date in THEDATE field with your current data in the other fields.

Related

Selecting data between the fixed date every month in SQL dynamically

I was using the below sql query to pull report for the last month.
Select * from TABLE
where datediff(month, InvoiceDate, Getdate()) = 1
I link this SQL query to Excel Power Query to generate the monthly report automatically by just 1 refresh click.
Now my issue is that our reporting has changed from 26th of last month to 25th of the current month, so the above SQL query will not give me the correct report. Plus I have to add the date every month to generate the report.
Is there a way to add the date in where clause dynamically to generate the report every month, so that my tool work the way it was working earlier
I have created a table and inserted values into that table.
Image for reference:
I fetched inserted values where invocedate is between 2022-09-01 and 2022-09-30 using below code.
declare #Startdate date=dateadd(MM, -1,getdate())
declare #Enddate date=dateadd(MM, -1,getdate())
declare #startingdate date = CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(#Startdate)-1),#Startdate))
declare #endingdate date = CONVERT(VARCHAR(25),DATEADD(dd,-(DAY(DATEADD(mm,1,#Enddate))),
DATEADD(mm,1,#Enddate)))
select * from report where invocedate between #startingdate AND #endingdate
Image for reference:

SQL Get all Saturdays between two Dates

I'm trying to find all the saturdays between two dates (inclusive) without using a loop.
For example, April 1, 2021, to May 1, 2021 should return:
04-03-2021
04-10-2021
04-17-2021
04-24-2021
05-01-2021
You can use datename
select *
from Table
where Datename(dw,Datecolumn)='Saturday'
and DateColumn >= start and Datecolumn < End;
Alternatively, if you just want to generate a list on the fly, you can do
declare #StartDate date = '20210401', #EndDate date = '20210501';
select DateAdd(day, rn-1, #StartDate)
from (
select Row_Number() over (order by object_id) rn
from sys.columns
) d
where rn - 1 <= DateDiff(day, #StartDate, #EndDate)
and DateName(dw, DateAdd(day, rn-1, #StartDate))='Saturday';
This first generates a list of numbers in the inner query by utilising one of several possible system tables to select just a row number. This is essentially building a numbers / tally table on the fly, and it's usually a good idea to have a permanent table like this available (a single column of integers starting at 1 and going up to a squintillion or whatever you need). You can see how this works by just highlighting the inner query and running it (F5 in SSMS).
An out query selects from this and filters the row numbers to just the right sequential range for the number of days between the two specified dates. Again, you can check this by highlighting the entire query except for the last line, you'll see it generates the list of dates between the specified start and end dates inclusively.
Finally the and criteria extracts the name of the day for each date and further filters the list of dates based on the day's name.

Calculate Recurring User For 12 Months with SQL

I'm trying to see if there is a better way to achieve what I am doing right now. For example, I need to know total number of users who have logged in for the past 12 months. So each user who has logged in at least once a month, for twelve months in a row would count towards the total.
The way I am doing this right now is: I query my table and get all user ids and timestamps of when they were active and return them to my c# code. Then with bunch of loops and LINQ I calculate the value (Its too much code to dump into this question and since I'm trying to get away from doing it in c# I don't believe there is a need for it).
Now this takes some time to run and I'm sure there has to be a better way to do this with SQL. I've searched but haven't found any SQL functions that let you count based on a recurring condition.
For an answer I'm hoping to either get an example or a link to a similar SO question or an article that talks about achieving this.
An example of MyUsersTable:
UserId | Timestamp
1 | '2018-12-23 00:00:00.000'
1 | '2018-11-23 00:00:00.000'
1 | '2018-10-23 00:00:00.000'
EDIT: I did thought of using SUM(CASE WHEN month = 1 and month = 2 and month = 3) but that seems also like not a great solution.
Expected Result:
Total number of users who were active at least once a month in the last 12 months.
If you need users who logged in every month in 2018:
select ut.userid
from MyUsersTable ut
where timestamp >= '2018-01-01' and timestamp < '2019-01-01'
group by ut.userid
having count(distinct month(timestamp)) = 12;
I'd count the distinct number of months a user logged in on:
SELECT userid
FROM mytable
WHERE YEAR(timestamp) = 2018
GROUP BY userid
HAVING COUNT(DISTINCT MONTH(timestamp)) = 12
To get userIDs who logged in for a specific number of consecutive months, you can use:
/* These are your input values */
DECLARE #searchDate date = '2018-12-15' ;
DECLARE #monthsToSearch int = 12 ;
/* First day of search month */
DECLARE #EndDate date = DATEADD(month, DATEDIFF(month, 0, #searchDate), 0) ;
/* First day of month to search from */
DECLARE #StartDate date = DATEADD(month, -#monthsToSearch, #EndDate) ;
SELECT userID --, #StartDate AS startDate, #EndDate AS endDate
FROM (
SELECT userID, ( (YEAR(userLoginDT)*100)+MONTH(userLoginDT) ) AS datePoint /* YYYYMM */
FROM t1
WHERE userLoginDT >= #StartDate
AND userLoginDT < #EndDate
) s1
GROUP BY userID
HAVING count(distinct(datePoint)) = #monthsToSearch
;
See the db<>fiddle here for my examples.
The fist two declared variables are your input variables. You feed it the date your are running the report on and then telling it how many months you want to go back to. So you can search any number of months. After that, it's pretty much date manipulation and math.
#EndDate essentially takes your declared date and calculates the first day of the month you are currently searching in. You will search for any dates before this date.
#StartDate counts back from your #EndDate to calculate the number of months you want to search.
(YEAR(userLoginDT)*100)+MONTH(userLoginDT) in your sub-select creates an integer variable that you can GROUP BY to get a distinct count of months you're searching over. This part could be sped up with the Calendar Table.
Then you just use the HAVING to pick out how many distinct records your want for #monthsToSearch.
NOTE: As many here can attest, I'm a huge fan of working with Calendar Tables when dealing with date calculations and large amounts of search data. Something like that would likely speed the query up a bit.

Facing issue in Hive query in generating missing dates

I have a requirement where I need to go back to previous values for a column until 1000 rows and get those previous 1000 dates for my next steps, but all those 1000 previous dates are not present for that column in the table. But I need those missing dates to get from output of the query.
When I try to run below query it is not displaying 1000 previous date values from current date.
Example: let's say only 2 dates are available for date column
date
2019-01-16
2019-01-19
I have come up with a query to get back 1000 dates but it is giving only nearest date as all previous back dates are missing
SELECT date FROM table1 t
WHERE
date >= date_sub(current_date,1000) and dt<current_date ORDER BY date LIMIT 1
If I run above query it is displaying 2019-01-16, since previous 1000 days back date are not present it is giving nearest date ,which is 2019-01-16 but I need missing dates starting from 2016-04-23 (1000th date from current date) till before current date (2019-01-18) as output of my query.
You can generate dates for required range in the subquery (see date_range subquery in the example below) and left join it with your table. If there is no record in your table on some dates, the value will be null, dates will be returned from the date_range subquery without gaps. Set start_date and end_date parameters for date_range required:
set hivevar:start_date=2016-04-23; --replace with your start_date
set hivevar:end_date=current_date; --replace with your end_date
set hive.exec.parallel=true;
set hive.auto.convert.join=true; --this enables map-join
set hive.mapjoin.smalltable.filesize=25000000; --size of table to fit in memory
with date_range as
(--this query generates date range, check it's output
select date_add ('${hivevar:start_date}',s.i) as dt
from ( select posexplode(split(space(datediff('${hivevar:end_date}','${hivevar:start_date}')),' ')) as (i,x) ) s
)
select d.dt as date,
t.your_col --some value from your table on date
from date_range d
left join table1 t on d.dt=t.date
order by d.dt --order by dates if necessary

SSRS SQL I need to display data for dates used in the parameter and the previous month

I have an SSRS report with parameters for Created On Start and Created On End. Users run this manually and choose the date range to display records for. I need to display in two different columnns the records for the month the user entered in the parameters and the previous month for the dates used in the parameters.
For example the user uses the the following dates in the parameters:
Start Date: 03/01/2016 EndDate: 03/31/2016
The Report should display in one column the records for march 2016 and next to it the records for february 2016
You could write one query which queries both months.
Add a field that will act as the column label eg format the date as the first of the month.
Then create a pivot table to show the two months as the columns with the usual rows .
EDIT - new details
So:
dateStart = '2016-03-01'
dateEnd = '2016-03-31'
These could be less than the whole month, but should be in the same month. prevStart = DATEADD(month, DATEDIFF(month, '2000-01-01', dateStart)-1, '2000-01-01')
the first day of the previous month.
Use similar for the prevEnd to calculate the last day of previous month.
OK. Now build your select:
SELECT xxxx, yyyy, zzzz
, DATEADD(month, DATEDIFF(month, '2000-01-01', createdOnDate), '2000-01-01') as MonthCol
FROM tables
WHERE (createdOnDate>= prevStart and createdOnDate<=prevEnd)
OR (createdOnDate>= dateStart and createdOnDate<=dateEnd)
Build a pivot table style grid with monthCol as the heading of the columns and your usual data as the rows. That way you can get your "previous Month" columns as well as the date range that you selected