Related
I am using below case condition to calculate a StartDate variable:
DECLARE #StartDate Date =
DATEADD(DAY, CASE WHEN DATEPART(dw, GETDATE()) = 2 THEN -10 ELSE -8 END, GETDATE())
AS you can see, if today's date is Monday then 10 days are subtracted from today's date, else 8 days are deducted. Since today (10/16/2018) is not a Monday, this would return 10/8/2018 as an output (8 days deduction). If executed on Monday (10/15) then #StartDate would return 10/5 as output.
I added a table called Holidays and it has two columns Holiday Name and Date containing three records for this year: Columbus Day: 10/8, Veteran day 11/12 and Thanksgiving 11/22.
Now the challenging part I have to do is, if the returned output of #StartDate is 10/8 (query executed today: 10/16) which is a holiday (Monday), then value of #StartDate should be changed to 10/5 (previous business day, Saturday & Sunday excluded). Also if the value of #StartDate is 10/5 (query executed on 10/15), then the value should be changed to 10/4 since 10/8 was a holiday, it won't be counted for deduction of 10 days so instead of 10/5, it should be 10/4.
So in theory it should work as: check if there are any holidays that fall between today's date and #StartDate, and if so then use prior day and adjust for Mondays accordingly based on the scenario I mentioned above.
Please note that the included statement I mentioned at the top is part of a stored procedure.
How can I make this work, can someone help? Thanks in advance.
Assuming that there are never multiple dates in a row in your holiday, this will do it in a single(ish) statement. You could easily break this into two if you prefer:
DECLARE #StartDate date
;with d as (
select convert(date,dateadd(day,case when datepart(dw,getdate())=2 then -10 else -8 end,getdate())) dt
)
select #StartDate=case when holiday.date is null then dt else dateadd(day,-1,dt) end
from d
left join holiday on holiday.date=dt
EDIT: This is a complete working copy. I create a table variable to hold holidays, run the initial query, then insert the returned date as a holiday, then run the query again. If you run this in sql server you will see that the second query returns the day before the first query.
declare #holiday table(date date)
DECLARE #StartDate date
;with d as (
select convert(date,dateadd(day,case when datepart(dw,getdate())=2 then -10 else -8 end,getdate())) dt
)
select #StartDate=case when holiday.date is null then dt else dateadd(day,-1,dt) end
from d
left join #holiday holiday on holiday.date=dt
select #startdate
insert #holiday values (#startdate)
;with d as (
select convert(date,dateadd(day,case when datepart(dw,getdate())=2 then -10 else -8 end,getdate())) dt
)
select #StartDate=case when holiday.date is null then dt else dateadd(day,-1,dt) end
from d
left join #holiday holiday on holiday.date=dt
select #startdate
In a calendar control, we can see some dates from the previous month and next month also. Sample image below
(ie Apr-2016: Starts from Mar-28 and ends in May-08
Mar-2016: Starts from Apr Feb-29 and ends in Apr-10)
Here, i need to generate a list of all the dates in a calendar control for a particular year month. My week start is Monday.
Here is the tsql script i have tried so far.
DECLARE #V_DATE DATE = GETDATE()
;WITH CTE_DATE AS (
SELECT DATEADD(dd,-(DAY(#V_DATE)-1),#V_DATE) CDATE
UNION ALL
SELECT DATEADD(dd,1,CDATE)
FROM CTE_DATE
WHERE DATEADD(dd,1,CDATE) <= DATEADD(dd,-(DAY(DATEADD(mm,1,CDATE))),DATEADD(mm,1,CDATE))
)
SELECT * FROM CTE_DATE
Result Is:
2016-04-01
2016-04-02
.
.
2016-04-29
2016-04-30
It will list all the days from a inputted year month, but i need to include the
missing dates from the previous month as well as next month.
Expected result for Apr-2016
2016-03-28
2016-03-29
.
2016-04-15
.
2016-05-07
2016-05-08
Expected result for May-2016
2016-04-25
2016-04-26
.
2016-05-15
.
2016-06-04
2016-06-05
Note:- The calendar control is always showing 42 days.
since your week is starts on Monday,you can take referece to date 0 '1900-01-01' which is a Monday. Adding 41 days would gives you your end date
select
date_fr = dateadd(day, datediff(day, 0, '2016-05-01') / 7 * 7, 0),
date_to = dateadd(day, datediff(day, 0, '2016-05-01') / 7 * 7, 41)
the following gives you date 1900-01-01 and Monday
select convert(datetime, 0), datename(weekday, 0)
Have you considered creating a dates table in your database. You would have columns for dates and a column for week number. Linking to this table you could find the week number for your start and end dates, you could then re-link to the table to find the first date of your start week and the last date of your end week. This would probably be more efficient than calculations at each step each time, it is a simple link.
I have create done script for this. This is working as per my expectation, may be helpful for future reference. (Thanks #Squirrel for the logic).
DECLARE #V_ST_DATE DATE = GETDATE()
SET #V_ST_DATE = DATEADD(DAY,-(DAY(#V_ST_DATE)-1),#V_ST_DATE)
SET #V_ST_DATE = DATEADD(WEEK,DATEDIFF(WEEK, 0, #V_ST_DATE) ,0) +
(CASE WHEN DATEADD(WEEK,DATEDIFF(WEEK, 0, #V_ST_DATE) ,0) > #V_ST_DATE THEN -7 ELSE 0 END)
;WITH CTE_DATE AS (
SELECT #V_ST_DATE CDATE,0 TDAYS
UNION ALL
SELECT DATEADD(DAY,1,CDATE) , DATEDIFF(DAY,#V_ST_DATE, DATEADD(DAY,1,CDATE))
FROM CTE_DATE
WHERE DATEDIFF(DAY,#V_ST_DATE, DATEADD(DAY,1,CDATE)) < 42
)
SELECT * FROM CTE_DATE
I'm attempting to calculate days of therapy by month from an oracle database. The (vastly simplified) data is as follows:
Therapies
+-----------+-----------+----------+
| Rx Number | StartDate | StopDate |
|-----------+-----------+----------|
| 1 | 12-29-14 | 1-10-15 |
| 2 | 1-2-15 | 1-14-15 |
| 3 | 1-29-15 | 2-15-15 |
+-----------+-----------+----------+
For the purposes of this example, all times are assumed to be midnight. The total days of therapy in this table is (10-1 + 32-29) + (14-2) + (15-1 + 32-29) = 41. The total days of therapy in January in this table is (10-1) + (14-2) + (32-29) = 24.
If I wanted to calculate days of therapy for the month of January , my best effort is the following query:
SELECT SUM(stopdate - startdate)
FROM therapies
WHERE startdate > to_date('01-JAN-15')
AND stopdate < to_date ('01-FEB-15');
However, rx's 1 and 3 are not captured at all. I could try the following instead:
SELECT SUM(stopdate - startdate)
FROM therapies
WHERE stopdate > to_date('01-JAN-15')
AND startdate < to_date ('01-FEB-15');
But that would include the full duration of the first and third therapies, not just the portion in January. To make the matter more complex, I need these monthly summaries over a period of two years. So my questions are:
How do I include overhanging therapies such that only the portion within the target time period is included, and
How do I automatically generate these monthly summaries over a two year period?
How do I include overhanging therapies such that only the portion
within the target time period is included?
select sum(
greatest(least(stopdate, date '2015-01-31' + 1)
- greatest(startdate, date '2015-01-01'), 0)) suma
from therapies
How do I automatically generate these monthly summaries over a two
year period?
with period as (select date '2014-01-01' d1, date '2015-12-31' d2 from dual),
months as (select trunc(add_months(d1, level-1), 'Month') dt
from period connect by add_months(d1, level-1)<d2)
select to_char(dt, 'yyyy-mm') mth,
sum(greatest(least(stopdate, add_months(dt, 1)) - greatest(startdate, dt), 0)) suma
from therapies, months
group by to_char(dt, 'yyyy-mm') order by mth
Above queries produced desired output. Please insert your dates in proper places to change analyzed periods.
In second SQL inner subquery months gives 24 dates, one for each month. The rest is only maneuvering
with functions greatest(),least() and some math.
Use a case statement to set the start date and stop date. Like the below:
select sum(
Stopdate -
(case Startdate
when startdate < to_date(#YourBeginingDate) then To_date(#YourBeginingDate)
else startdate
end)
FROM therapies
WHERE stopdate > to_date(#YourBeginingDate)
AND StartDate < to_date(#YourEndingDate)
I would do something like the following:
WITH t1 AS (
SELECT 1 AS rx, DATE'2014-12-29' AS start_date
, DATE'2015-01-10' AS stop_date
FROM dual
UNION ALL
SELECT 2, DATE'2015-01-02', DATE'2015-01-14'
FROM dual
UNION ALL
SELECT 3, DATE'2015-01-29', DATE'2015-02-15'
FROM dual
)
SELECT TRUNC(rx_dt, 'MONTH') AS rx_month, SUM(rx_cnt) AS rx_day_cnt
FROM (
SELECT rx_dt, COUNT(*) AS rx_cnt
FROM (
SELECT rx, start_date + LEVEL - 1 AS rx_dt
FROM t1
CONNECT BY start_date + LEVEL - 1 < stop_date
AND PRIOR rx = rx
AND PRIOR DBMS_RANDOM.VALUE IS NOT NULL
) GROUP BY rx_dt
) GROUP BY TRUNC(rx_dt, 'MONTH')
ORDER BY rx_month
Results:
12/1/2014 12:00:00 AM 2
1/1/2015 12:00:00 AM 24
2/1/2015 12:00:00 AM 15
See SQL Fiddle here.
What I am doing is using LEVEL and CONNECT BY to get all the days of therapy based on start_date and stop_date (not inclusive). I then GROUP BY the therapy date (rx_dt) to handle the overlapping therapies. Then I GROUP BY the month of the therapy using the TRUNC() function.
This should work just fine over a two-year period (or more); just add that filter before the last GROUP BY:
WHERE rx_dt >= DATE'2014-01-01'
AND rx_dt < DATE'2016-01-01'
GROUP BY TRUNC(rx_dt, 'MONTH')
Note that if your primary key is composite, you should include all the columns in the CONNECT BY clause:
CONNECT BY start_date + LEVEL - 1 < stop_date
AND PRIOR rx = rx
AND PRIOR patient_id = patient_id
--etc.
This is a bit tricky, as you need to capture days from sessions that:
Begin before the month and end after the month
Begin before the month and end during the month
Begin during the month and end after the month
Begin during the month and end during the month
To get those sessions, you can use a WHERE statement like this (the # symbol means that those are variables being passed in):
*examples are in TSQL, PLSQL might have somewhat different syntax
WHERE startdate < #endDate AND stopdate > #startDate
That should capture all four of those scenarios that I listed.
Then you only need to capture days that occurred during the month. I do this with a query that replaces the startdate/enddate with the date range limits if they exceed the range, like this:
SELECT
CASE WHEN enddate > #endDate then #endDate ELSE enddate END -
CASE WHEN startdate < #startDate THEN #startDate ELSE startdate END
So your whole query should look like this:
SELECT
SUM(
CASE WHEN enddate > #endDate then #endDate ELSE enddate END -
CASE WHEN startdate < #startDate THEN #startDate ELSE startdate END
)
FROM therapies
WHERE startdate < #endDate AND stopdate > #startDate
If you want to run that for two years, toss that code in a function that accepts #startDate and #endDate parameters, then call it from a query that gives you two years worth of months, like this:
WITH dateCTE AS (
SELECT
GETDATE() AS StartDate,
DATEADD(Month, 1, GETDATE()) AS EndDate
UNION ALL
SELECT
DATEADD(MONTH, -1, StartDate),
DATEADD(MONTH, -1, EndDate)
FROM dateCTE
WHERE StartDate > DATEADD(YEAR, -2, GETDATE())
)
SELECT
StartDate,
EndDate,
SomeFunction(StartDate, EndDate)
FROM dateCTE
I have a table Named Product_Sales and it holds data like this
Product_ID | Sold_by | Qty | From_date | To_date
-----------+---------+-----+------------+-----------
3 | 12 | 7 | 2013-01-05 | 2013-01-07
6 | 22 | 14 | 2013-01-06 | 2013-01-10
8 | 11 | 9 | 2013-02-05 | 2013-02-11
Now what is the query if I want to select sales data between two dates from a date range?
For example, I want to select sales data from 2013-01-03 to 2013-01-09.
As you can see, there are two ways to get things done:
enlist all acceptable options
exclude all wrong options
Obviously, second way is much more simple (only two cases against four).
Your SQL will look like:
SELECT * FROM Product_sales
WHERE NOT (From_date > #RangeTill OR To_date < #RangeFrom)
SELECT * from Product_sales where
(From_date BETWEEN '2013-01-03'AND '2013-01-09') OR
(To_date BETWEEN '2013-01-03' AND '2013-01-09') OR
(From_date <= '2013-01-03' AND To_date >= '2013-01-09')
You have to cover all possibilities. From_Date or To_Date could be between your date range or the record dates could cover the whole range.
If one of From_date or To_date is between the dates, or From_date is less than start date and To_date is greater than the end date; then this row should be returned.
Try following query to get dates between the range:
SELECT *
FROM Product_sales
WHERE From_date >= '2013-01-03' AND
To_date <= '2013-01-09'
SELECT * FROM Product_sales
WHERE From_date between '2013-01-03'
AND '2013-01-09'
This covers all conditions that you are looking for.
SELECT * from Product_sales where (From_date <= '2013-01-09' AND To_date >= '2013-01-01')
SELECT *
FROM Product_sales
WHERE (
From_date >= '2013-08-19'
AND To_date <= '2013-08-23'
)
OR (
To_date >= '2013-08-19'
AND From_date <= '2013-08-23'
)
Please try:
DECLARE #FrmDt DATETIME, #ToDt DATETIME
SELECT #FrmDt='2013-01-03', #ToDt='2013-01-09'
SELECT *
FROM Product_sales
WHERE (#FrmDt BETWEEN From_date AND To_date) OR
(#ToDt BETWEEN From_date AND To_date)
This is easy, use this query to find select data from date range between two dates
select * from tabblename WHERE (datecolumn BETWEEN '2018-04-01' AND '2018-04-5')
Just my 2 cents, I find using the "dd-MMM-yyyy" format safest as the db server will know what you want regardless of the regional settings on the server. Otherwise you could potentially run into issues on a server that has its date regional settings as yyyy-dd-mm (for whatsoever reason)
Thus:
SELECT * FROM Product_sales
WHERE From_date >= '03-Jan-2013'
AND To_date <= '09-Jan-2013'
It's always worked well for me ;-)
select *
from table
where
( (table.EndDate > '2013-01-05') and (table.StartDate < '2013-01-07' ) )
Check this query, i created this query to check whether the check in date over lap with any reservation dates
SELECT * FROM tbl_ReservedRooms
WHERE NOT ('#checkindate' NOT BETWEEN fromdate AND todate
AND '#checkoutdate' NOT BETWEEN fromdate AND todate)
this will retrun the details which are overlaping , to get the not overlaping details then remove the 'NOT' from the query
This query will help you:
select *
from XXXX
where datepart(YYYY,create_date)>=2013
and DATEPART(YYYY,create_date)<=2014
This working on SQL_Server_2008 R2
Select *
from Product_sales
where From_date
between '2013-01-03' and '2013-01-09'
SELECT NULL
FROM HRMTable hm(NOLOCK)
WHERE hm.EmployeeID = 123
AND (
(
CAST(#Fromdate AS date) BETWEEN CAST(hm.FromDate AS date)
AND CAST(hm.ToDate AS date)
)
OR (
CAST(#Todate AS date) BETWEEN CAST(hm.FromDate AS date)
AND CAST(hm.ToDate AS date)
)
)
)
You can also try using following fragments:
select * from Product_sales
where From_date >= '2013-01-03' and game_date <= '2013-01-09'
Here is a query to find all product sales that were running during the month of August
Find Product_sales there were active during the month of August
Include anything that started before the end of August
Exclude anything that ended before August 1st
Also adds a case statement to validate the query
SELECT start_date,
end_date,
CASE
WHEN start_date <= '2015-08-31' THEN 'true'
ELSE 'false'
END AS started_before_end_of_month,
CASE
WHEN NOT end_date <= '2015-08-01' THEN 'true'
ELSE 'false'
END AS did_not_end_before_begining_of_month
FROM product_sales
WHERE start_date <= '2015-08-31'
AND end_date >= '2015-08-01'
ORDER BY start_date;
DECLARE #monthfrom int=null,
#yearfrom int=null,
#monthto int=null,
#yearto int=null,
#firstdate DATE=null,
#lastdate DATE=null
SELECT #firstdate=DATEADD(month,#monthfrom-1,DATEADD(year,#yearfrom-1900,0)) /*Setting First Date using From Month & Year*/
SELECT #lastdate= DATEADD(day,-1,DATEADD(month,#monthto,DATEADD(year,#yearto-1900,0)))/*Setting Last Date using From Month & Year*/
SELECT * FROM tbl_Record
WHERE (DATEADD(yy, Year - 1900, DATEADD(m, Month - 1, 1 - 1)) BETWEEN CONVERT(DATETIME, #firstdate, 102) AND
CONVERT(DATETIME, #lastdate, 102))
You should compare dates in sql just like you compare number values,
SELECT * FROM Product_sales
WHERE From_date >= '2013-01-01' AND To_date <= '2013-01-20'
this is easy, use this query to find what you want.
select * from Product_Sales where From_date<='2018-04-11' and To_date>='2018-04-11'
The table:
hDate Holiday
17/12/2011 National Day
01/01/2012 New Year
....
From the table, i want to find the total number of holidays between two dates:
A query like:
select count(hdate)
from table1
where hdate between '" & start_date & "' and '" & end_date & "'
User input:
start_date = '16/12/2011'
end_date = '15/01/2012'
and also I want to find the friday between 2 dates.
For finding fridays, how to create a query?
Expected output:
Holiday Friday
2 5
[2] - 2 days holiday from table1, [5] - 5 days friday
How to do this?
This counts the fridays between 2 dates:
declare #from datetime= '2012-01-26'
declare #to datetime = '2012-01-28'
select datediff(day, -3, #to)/7-datediff(day, -2, #from)/7
The holidays are easy to find, it seems like you have that part covered already.
I sort of answered this earlier. But didn't get any credit:
How to calculate the number of "Tuesdays" between two dates in TSQL?
That select help you:
DECLARE #FROMDATE DATE = '2009-01-07'
DECLARE #TODATE DATE = '2012-01-26'
SELECT COUNT(*) holidays,(select COUNT(*) from table1 where DATEPART(DW, hdate) = 5
AND DT BETWEEN #FROMDATE AND #TODATE ) fridays FROM table1
WHERE hdate BETWEEN #FROMDATE AND #TODATE
See:
Why should I consider using an auxiliary calendar table?
A calendar table can make it much
easier to develop solutions around any
business model which involves dates.
Last I checked, this encompasses
pretty much any business model you can
think of, to some degree. Constant
problems that end up requiring
verbose, complicated and inefficient
methods include the following
questions:
How many business days between x and y?
What are all of the dates between the second Tuesday of March and the first Friday in April?
On what date should I expect this shipment to arrive?
What were the dates of all the Fridays in this quarter?
...
For the holiday, your SQL looks fine, you just seem to have trouble plugging the parameters into the SQL. If you specify which programming language you are using, we might be able to help here. If you use .NET, you should use Parameterized Queries instead of string substitution.
For the fridays, see this question:
Get number of weekdays (Sundays, Mondays, Tuesdays) between two dates SQL
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SET #StartDate ='16/12/2011'
SET #EndDate = '15/01/2012'
SELECT
(DATEDIFF(dd, #StartDate, #EndDate) + 1)
-(DATEDIFF(wk, #StartDate, #EndDate) * 2)
-(CASE WHEN DATENAME(dw, #StartDate) = 'Friday' THEN 1 ELSE 0 END)
select count(Holiday) as holiday
from Table1
where date between start_date AND end_date
We solving the problem with an extra time table. This looks like this
ID | Date | Holiday | Year | CalendarWeek | DayName
1 | 17/12/2011 | 1 | 2011 | 50 | Monday
2 | 18/12/2011 | 0 | 2011 | 50 | Thursday
3 | 19/12/2011 | 0 | 2011 | 50 | Wendsday
With this table you could resolve your question like this
select
(select count(d.DayName) from date_table as d
where d.DayName = 'Friday' and date >= start_date and date <= end_date ),
(select sum(d.Holiday) from date_table as d
where date >= start_date and date <= end_date )
This should also be SQL Server 2000 compatible. And this for SQL Server 2005 and above:
with tmp(id) as
(
select id from from date_table where date >= start_date and date <= end_date
)
select
(select count(d.DayName) from date_table inner join tmp on tmp.id = id
where DayName = 'Friday' ),
(select sum(d.Holiday) from date_table inner join tmp on tmp.id = id )