I am racking my brain on this one. I have a list of campaigns and their associated start and end dates. I'm trying to write a query to list the campaigns where at least one day between the start and end date was in 2017. My original thought was just use datepart():
datepart(yyyy,StartDt = 2017) OR datepart(yyyy,EndDt = 2017)
But that wont pick up a campaign that started before 2017 and ended after 2017, like start date 1/1/2016 and end date 1/1/2018.
Probably the easiest way to do this is like this (it's something I use when having to do temporal table queries):
WHERE CampaignStartDate < '2018-01-01'
AND CampaignEndDate >= '2017-01-01'
This guarantees that your campaign start and end dates had at least some overlap with the 2017 year. It's a good way of testing if two time ranges overlap at all.
Related
I work for a company where everyday I modify a query by changing the date of the day before, because the report is always from the previous day.
I want to automate the date change. I have made a table with two columns, one with all dates from this year and another with bits where if 0 is a working day and 1 if is a holiday.
I have successfully automated a little bit by telling if the day before is a working day then subtract 1 from the date (This is what happens everyday). But the problem is, that if is Monday appears as Friday, because Saturday and Sunday are not billable. And let's also say, that if today is Thursday and Wednesday and Tuesday we're holidays, then the report will run on Monday. I will leave you a picture, that shows how the table is made with dates.
Remembering, that if there is no holidays in the middle of the week, always will be subtract one.
The way to do this sort of thing is close to what you have done, but just extend it further. Create a BusinessDate table that has every date, and then every rule you have implemented inside it. You can go so far as to include a column such as ReportDate which will return,for every date, what date the report should be run for.
Do this once, and it will work forever more. You may have to update for future holidays once a year, but better than once a day!
It will also allow you to update things specific for your business, like quarter dates, company holidays, etc.
If you want to know more on the subject, look up topics around creating a date dimension in a data warehouse. Its the same general issue you are facing.
Too complicated for a comment and it involves a lot of guessing.
So everyday, your process starts by first determining if "today" is a work day. So you would do something like:
if exists (select * from <calendar> where date = cast (getdate() as date) and IsWorkday = 1")
begin
<do stuff>
end;
The "do stuff" section would then run a report or your query (or something that isn't very clear) using the most recent work day prior to the current date. You find that date using something like:
declare #targetdate date;
set #targetdate = (select max(date) from <calendar>
where date < cast (getdate() as date)
and IsWorkday = 1);
if #targetdate is not null
<run your query using #targetdate>
That can be condensed into less code but it is easier to understand when the logic is written step-by-step.
I am using datepart function in SP. It is used to compare week and year of specified date.
Now my query arise as new year starts. I have one table called 'Task' and it is storing tasks date wise. Now When I execute SP with DATEPART(YY,'2016-01-05') . It is giving proper 2016's data. But I execute it with DATEPART(ISOWK,'2016-01-05') , it is giving 2015's data also with 2016's data.
I want data from 28th dec,2015 to 2nd jan,2016. Data of the week. And I am not able get data of 1st and 2nd Jan in that. Please help me with this.
Thanks,
ISOWK return the week number
You are trying to get date from 2015-12-28 to 2016-01-02.
The week number of 2015-12-28 is 53 and 2016-01-02 is 53
If you already have your start and end dates decided then you could use a simple query as shown below to filter on date range.
When mentioning date string in your query make sure you stick to this format :yyyymmdd which SQL Server will automatically understand. You don't need DATEPART to get records between two dates.
Query for filtering on a date range
SELECT TaskID, TaskDescription
FROM Tasks
where TaskDate between '20151228' and '20160102'
Another query you can use for date range filtering
SELECT TaskID, TaskDescription
FROM Tasks
where TaskDate >= '20151228' and TaskDate <= '20160102'
I have a table in a database with one column containing dates and another one containing scores. Basically, what I want to do is grab the best score in a given week.
Weeks can start on any given day (From Friday to Thursday, for instance), and that is defined by the user.
Here is what I have so far:
SELECT MAX(Series), DATE(DATE(Date, 'weekday 0'), '-7 days') dateStartOfWeek FROM SeriesScores
WHERE Season = '2010-2011'
AND dateStartOfWeek = '2010-08-29'
GROUP BY DateStartOfWeek
Where Series is the column containing the scores and Date is the (badly) named actual date.
The problem with this query is that it works for every day except for the day the week is supposed to be starting on.
For example: 2010-08-29 is a Sunday and in this example, I'm trying to find on which date the Sunday of the given week is. My function works for every day of that week except for 2010-08-29 (Sunday) since it tries to find the next day that is a Sunday (itself in this case). To compensate for that, I go back 7 days to get the correct Sunday, which creates the error for the already correct Sunday since this one doesn't need to go back 7 days or else it is one week off.
I figured I could solve this problem easily using Java, but I want to see how it should be done using SQL instead.
My solution (I don't even know if it can be done), would be to check if date and dateStartOfWeek are the same. If they are, don't substract 7 days from the date. If they're not, do as I did in my example. I don't know how to use conditions such as this one in SQL, though, and this is where I need help.
Thanks a lot in advance!
I think you need to use CASE operator - see http://sqlite.awardspace.info/syntax/sqlitepg09.htm
EDIT - try:
SELECT MAX(Series), CASE WHEN STRFTIME ( '%w', Date ) = 0 THEN DATE(Date, 'weekday 0') ELSE DATE(DATE(Date, 'weekday 0'), '-7 days') END AS dateStartOfWeek FROM SeriesScores
WHERE Season = '2010-2011'
AND dateStartOfWeek = '2010-08-29'
GROUP BY DateStartOfWeek
see http://www.sqlite.org/lang_datefunc.html
I have a "workDate" field and a "receivedDate" field in table "tblExceptions." I need to count the number of days beteen the two. workDate always comes first - so, in effect, it's kind of like workDate is "begin date" and receivedDate is "end date". Some exclusions make it tricky to me though:
First, I need to exclude holidays. i do have a table called "tblHolidays", with one field - holidayDate. I have holidays stored up through next year, so maybe I can incorporate that into the query?
Also, most flummoxing is that work dates can never occur on weekends, but received dates can. So, i somehow need to exclude weekends when i'm counting, but allow for a weekend if the received date happens to fall on a saturday or sunday. so, if the work date is June 3rd, 2011, and received date is June 11th, 2011, the count of valid days would be 7, not 9.
Any help on this is much appreciated. Thanks!
Something like this should give you the number of days with the holidays subtracted:
select
days = datediff(day, workDate, receivedDate)
- (select count(*) from tblHolidays where holidayDate >= workDate and holidayDate < receivedDate)
from
tblExceptions
Note that the date functions differ between database systems. This is based on MS SQL Server, so it may need adapting if you are using some other database.
If you have a table full of dates to include (non-weekends, non-holidays, etc.) and you knew when the 'begin' date and the 'end' date is, then you can do something roughly like this:
select count(*) from tblIncludedDates where beginDateValue <= dateField and endDateValue >= dateField
to get the number of valid days between those dates.
I have an interesting query to do and am trying to find the best way to do it. Basically I have an absence table in our personnel database this records the staff id and then a start date and end date for the absence. End date being null if not yet entered (not returned). I cannot change the design.
They would like a report by month on number of absences (12 month trend). With staff being off over the month change it obviously may be difficult to calculate.
e.g. Staff off 25/11/08 to 05/12/08 (dd/MM/yy) I would want the days in November to go into the November count and the ones in December in the December count.
I am currently thinking in order to count the number of days I need to separate the start and end date into a record for each day of the absence, assigning it to the month it is in. then group the data for reporting. As for the ones without an end date I would assume null is the current date as they are presently still absent.
What would be the best way to do this?
Any better ways?
Edit: This is SQL 2000 server currently. Hoping for an upgrade soon.
I have had a similar issue where there has been a table of start/end dates designed for data storage but not for reporting.
I sought out the "fastest executing" solution and found that it was to create a 2nd table with the monthly values in there. I populated it with the months from Jan 2000 to Jan 2070. I'm expecting it will suffice or that I get a large pay cheque in 2070 to come and update it...
DECLARE TABLE months (start DATETIME)
-- Populate with all month start dates that may ever be needed
-- And I would recommend indexing / primary keying by start
SELECT
months.start,
data.id,
SUM(CASE WHEN data.start < months.start
THEN DATEDIFF(DAY, months.start, data.end)
ELSE DATEDIFF(DAY, data.start, DATEADD(month, 1, months.start))
END) AS days
FROM
data
INNER JOIN
months
ON data.start < DATEADD(month, 1, months.start)
AND data.end > months.start
GROUP BY
months.start,
data.id
That join can be quite slow for various reasons, I'll search out another answer to another question to show why and how to optimise the join.
EDIT:
Here is another answer relating to overlapping date ranges and how to speed up the joins...
Query max number of simultaneous events