Distribute amount monthly with respect to start date and end date - sql

I have table as
Project_ID
Start_Date
End_Date
BUDGET_Amount
For example:
I Need to Return with SQL 12 Row Each Row Represent the Month-Year between the Two Date and the Value of Budget = 1200 / No of months between two dates "12" = 100$
So The Result to be like this
Proj_ID , START_DATE , END_DATE , AMOUNT
"1","1-JAN-2017","31-JAN-2017",100$
"1","1-FEB-2017","27-FEB-2017",100$m
"1","1-MAR-2017","31-MAR-2017",100$
"1","1-APR-2017","31-APR-2017",100$
"1","1-MAY-2017","31-MAY-2017",100$
"1","1-JUN-2017","31-JUN-2017",100$
"1","1-JUL-2017","31-JUL-2017",100$
"1","1-AUG-2017","31-AUG-2017",100$
"1","1-SEP-2017","31-SEP-2017",100$
"1","1-OCT-2017","31-OCT-2017",100$
"1","1-NOV-2017","31-NOV-2017",100$
"1","1-DEC-2017","31-DEC-2017",100$

Using Common Table Expression(CTE) you can generate dates in given range. This will generate the output you need:
;with mycte as
(
select cast('1 jan 2017' as datetime) as DateValue
union all
select DATEADD(MONTH,1, DateValue)
from mycte
where DATEADD(MONTH,1, DateValue) <= '31 dec 2017'
)
select
1 Proj_ID,
REPLACE(CONVERT(VARCHAR(11), DateValue, 106), ' ', '-') START_DATE ,
REPLACE(CONVERT(VARCHAR(11), DATEADD(DAY, -1, DATEADD(MONTH,1, DateValue))), ' ', '-') END_DATE ,
'100$' AMOUNT
from mycte
This is will display months' first and last days.

Related

Get sum of qty based on hour window

I'm working on a problem to figure out how much qty of product was created and dispatched between certain hours. For example, I need to see how much was created (by created I mean how many orders were created with X qty) between 6pm today and 3pm tomorrow. I'm trying to create a time bin for this but whatever I try isn't working out.
select CREATE_DATE
, CREATE_TIME
, RELEASED_DATE
, RELEASED_TIME
, sum(case
when CREATE_DATE = DATEADD(DAY, DATEDIFF(DAY, 0, CREATE_DATE), 0)
and CREATE_TIME >= '18:00:00' AND CREATE_DATE = DATEADD(DAY, DATEDIFF(DAY, 0, CREATE_DATE), 1)
then ORDER_QTY
when CREATE_DATE = DATEADD(DAY, DATEDIFF(DAY, 0, CREATE_DATE), 1)
and CREATE_TIME <= '14:59:59'
then ORDER_QTY
end) as small_window_qty
, sum(ORDER_QTY) as ord_qty
, sum(RELEASED_QTY) as rls_qty
from table
Any help with this would be appreciated. Just need a way to organize the days into the following buckets: Normal Hour Window = Created 6pm to 6pm; Smaller Hour Window = Created 6pm to 3pm; Agreed Upon = Dispatch by 3pm (12am to 3pm)
Edit: Some clarification. What im trying to accomplish is a root cause analysis. We have orders that create every day, and must ship within 2 days of being created. We're trying to figure out why our orders are not shipping on time. So as an RCA, Im trying to dig into the orders, when they were created, when they were dispatched(or released, same thing) and when they shipped. The Hour Window's mentioned above are cutoff times for orders to be created for a certain day. Example:
300 units were created today, and they must ship 2 days from now. I want to see, of that 300 created, how many were created before 3pm, and of that, how much dispatched by 3pm same day. Hope that clarifies things. Not everything that is created must be dispatched the same day, as we have 2 days to ship the orders.
you're leaving a lot of info out so i'm filling in the blanks and making assumptions here. doublecheck that my data types line up with your data types.
create table sales (create_date date, create_time time, released_date date, released_time time, qty int)
insert sales
select '1/14/13','18:45','1/15/13','10:45', 10
union all
select '1/14/13','19:45','1/15/13','12:45', 12
union all
select '1/15/13','19:15','1/16/13','16:45', 6
union all
select '1/15/13','18:00','1/16/13','14:45', 25
union all
select '1/15/13','18:45','1/16/13','15:00', 3
union all
select '1/16/13','19:45','1/17/13','16:30', 1
union all
select '1/16/13','20:45','1/17/13','17:45', 9
union all
select '1/17/13','18:30','1/18/13','18:00', 17
union all
select '1/18/13','18:30','1/19/13','17:15', 15
union all
select '1/18/13','18:45','1/19/13','19:15', 21
with base as
(
select *
, cast(create_date as datetime) + cast(create_time as datetime) as createtime
, cast(released_date as datetime) + cast(released_time as datetime) as releasetime
, datediff(hour,cast(create_date as datetime) + cast(create_time as datetime),cast(released_date as datetime) + cast(released_time as datetime)) as hrs
from sales
),
base2 as
(
select qty
, case
when create_time >= '18:00' and hrs <= 21 then 'small'
when create_time >= '18:00' and hrs <= 24 then 'normal'
else 'outside'
end as orderwindow
, case
when hrs between 6 and 21 then 'pass'
else 'fail'
end as agreedupon
from base
)
select sum(qty) as qty, orderwindow, agreedupon
from base2
group by orderwindow, agreedupon
drop table sales
this should give you the end result of being able to tell how much was created, what window of time it falls into, and if released by 3pm. adjust as needed.
i didn't want the code to get messy and convoluted so i used 2 CTEs.
I am not sure about your expected result and also your input data looks messay and not clear. So I used the data provided by the above answer. It looks you get running sum. If you can review the answer and get back to me if you need more modifications that is good. I suggest you to edit your Question and be more clear with your sample data and expected answer. Add more details to the question.
create table sales (create_date date, create_time time, released_date date, released_time time, qty int)
INSERT INTO sales
select '1/14/13','18:45','1/15/13','10:45', 10
union all
select '1/14/13','19:45','1/15/13','12:45', 12
union all
select '1/15/13','19:15','1/16/13','16:45', 6
union all
select '1/15/13','18:00','1/16/13','14:45', 25
union all
select '1/15/13','18:45','1/16/13','15:00', 3
union all
select '1/16/13','19:45','1/17/13','16:30', 1
union all
select '1/16/13','20:45','1/17/13','17:45', 9
union all
select '1/17/13','18:30','1/18/13','18:00', 17
union all
select '1/18/13','18:30','1/19/13','17:15', 15
union all
select '1/18/13','18:45','1/19/13','19:15', 21
SELECT
create_date
, create_time
, released_date
, released_time
,SUM(QTY) OVER ( PARTITION BY A.[Dispatched Window] ORDER BY released_date ) AS [Sum_qty]
,Qty
FROM
(
SELECT
create_date
, create_time
, released_date
, released_time
, CASE WHEN released_date BETWEEN CONVERT(DATETIME, CONVERT(CHAR(8), create_date, 112) + ' ' + CONVERT(CHAR(8), '18:00:00.0000000' , 108)) AND CONVERT(DATETIME, CONVERT(CHAR(8), DATEADD(DAY,1, create_date), 112) + ' ' + CONVERT(CHAR(8), '18:00:00.0000000' , 108)) THEN 'Normal Window'
WHEN released_date BETWEEN CONVERT(DATETIME, CONVERT(CHAR(8), create_date, 112) + ' ' + CONVERT(CHAR(8), '17:59:00.0000000' , 108)) AND CONVERT(DATETIME, CONVERT(CHAR(8), DATEADD(DAY,1, create_date), 112) + ' ' + CONVERT(CHAR(8), '15:00:00.0000000' , 108)) THEN 'Smaller Window'
WHEN released_date BETWEEN CONVERT(DATETIME, CONVERT(CHAR(8), create_date, 112) + ' ' + CONVERT(CHAR(8), '00:00:00.0000000' , 108)) AND CONVERT(DATETIME, CONVERT(CHAR(8), create_date, 112) + ' ' + CONVERT(CHAR(8), '15:00:00.0000000' , 108)) THEN 'Aggreed AUpon'
ELSE 'N/A'
END AS [Dispatched Window]
, Qty
FROM dbo.sales
) AS A

SQL Server: whole weeks total in a calendar month

I want weekly totals in a month. It will not include any partial week or future weeks. Week starts from Monday to Sunday.
I have a table structure like
Date Value -- Comments
----------------------------------------------------------------------
2016-10-01 7 Ignore this because its not a whole week in a month
2016-10-05 8 Week 1
2016-10-07 5 Week 1
2016-10-11 2 Week 2
2016-10-15 1 Week 2
2016-10-17 9 Ignore this because the week is not finished yet
OUTPUT
WeekNo Total
41 13
42 3
The easier way would be to build a Tally "date" table.
you can generate it from any Tally Table like:
DECLARE #StartDate DATE = '20160101'
, #EndDate DATE = '20161231';
WITH cte AS (
SELECT DATEADD(DAY, n - 1, #StartDate) AS date
FROM tally
WHERE n - 1 <= DATEDIFF(DAY, #StartDate, #EndDate)
)
SELECT
c.date
,YEAR(c.date) AS Year
,MONTH(c.date) AS Month
,DAY(c.date) AS Month
,DATEPART(WEEK,c.date) AS Week
,CASE WHEN 7<>COUNT(c.date) OVER (PARTITION BY YEAR(c.date),MONTH(c.date),DATEPART(WEEK,c.date)) THEN 0 ELSE 1 END AS isFullWeek
FROM cte c
Then you just need to Join it to what ever query you need.
DECLARE #StartDate datetime = '2011-10-01';
DECLARE #EndDate datetime = '2016-10-31';
SELECT
CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 2, tblData.RecordDate) AS date) AS WeekStart,
CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 8, tblData.RecordDate) AS date) AS WeekEnd,
SUM(Value) AS Total
FROM tblData
WHERE (#StartDate IS NULL
OR CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 2, tblData.RecordDate) AS date) >= CAST(#StartDate AS date))
AND (#EndDate IS NULL
OR CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 8, tblData.RecordDate) AS date) <= CAST(#EndDate AS date))
AND CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 8, tblData.RecordDate) AS date) < CAST(GETDATE() AS date)
GROUP BY CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 2, tblData.RecordDate) AS date),
CAST(DATEADD(dd, -DATEPART(dw, tblData.RecordDate) + 8, tblData.RecordDate) AS date)
Create a calendar table that meets your request, like this:
create table calendarTable ([date] date, weekNro int)
go
insert into calendarTable
select dateadd(d,n,'20160101'), DATEPART(WK,dateadd(d,n,'20151231'))
from numbers where n<500
If you don't have a Numbers Table, you must create it first. like this
SET NOCOUNT ON
CREATE TABLE Numbers (n bigint PRIMARY KEY)
GO
DECLARE #numbers table(number int);
WITH numbers(number) as (
SELECT 1 AS number
UNION all
SELECT number+1 FROM numbers WHERE number<10000
)
INSERT INTO #numbers(number)
SELECT number FROM numbers OPTION(maxrecursion 10000)
INSERT INTO Numbers(n) SELECT number FROM #numbers
Then query your table joining calendar table having in mind actual date for completed week, like this:
Similar to #Kilren but translated into postgres and using generate series from https://stackoverflow.com/a/11391987/10087503 to generate the dates
DECLARE #StartDate DATE = '20160101'
, #EndDate DATE = '20161231';
WITH cte AS (
SELECT i::date AS date FROM generate_series(#StartDate,
#EndDate, '1 day'::interval) i
)
SELECT
c.date
,DATE_TRUNC('month' ,c.date) AS month_trunc
,DATE_PART('week',c.date) AS week
,CASE WHEN 7<>COUNT(c.date)
OVER (PARTITION BY DATE_TRUNC('month' ,c.date),DATE_PART('week',c.date))
THEN 0 ELSE 1 END AS is_full_week
FROM cte c
Select DATEPART(ww, date) , SUM(Case When Comments Like '%1' then Value when Comments Like '%2' then Value else Value end)
from schema.tablename
group by DATEPART(ww,date)
I'm sorry if this doesn't work, it's the only way I thought to structure it.

How to get the summation of days in specific month of year in range

If i have Vacation table with the following structure :
emp_num start_date end_date
234 8-2-2015 8-5-2015
234 6-28-2015 7-1-2015
234 8-29-2015 9-2-2015
115 6-7-2015 6-7-2015
115 8-7-2015 8-10-2015
considering date format is: m/dd/yyyy
How could i get the summation of vacations for every employee during specific month .
Say i want to get the vacations in 8Aug-2015
I want the result like this
emp_num sum
234 7
115 4
7 = all days between 8-2-2015 and 8-5-2015 plus all days between 8-29-2015 AND 8-31-2015 the end of the month
i hope this will help you
declare #temp table
(emp_num int, startdate date, enddate date)
insert into #temp values (234,'8-2-2015','8-5-2015')
insert into #temp values (234,'6-28-2015','7-1-2015')
insert into #temp values (234,'8-29-2015','9-2-2015')
insert into #temp values (115,'6-7-2015','6-7-2015')
insert into #temp values (115,'8-7-2015','8-10-2015')
-- i am passing 8 as month number in your case is August
select emp_num,
SUM(
DATEDIFF (DAY , startdate,
case when MONTH(enddate) = 8
then enddate
else DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,startdate)+1,0))--end date of month
end
)+1) AS Vacation from #temp
where (month(startdate) = 8 OR month(enddate) = 8) AND (Year(enddate)=2015 AND Year(enddate)=2015)
group by emp_num
UPDATE after valid comment: This will fail with these dates: 2015-07-01, 2015-09-30 –#t-clausen.dk
i was assumed OP wants for month only which he will pass
declare #temp table
(emp_num int, startdate date, enddate date)
insert into #temp values (234,'8-2-2015','8-5-2015')
insert into #temp values (234,'6-28-2015','7-1-2015')
insert into #temp values (234,'8-29-2015','9-2-2015')
insert into #temp values (115,'6-7-2015','6-7-2015')
insert into #temp values (115,'8-7-2015','8-10-2015')
insert into #temp values (116,'07-01-2015','9-30-2015')
select emp_num,
SUM(
DATEDIFF (DAY , startdate,
case when MONTH(enddate) = 8
then enddate
else DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,startdate)+1,0))
end
)+1) AS Vacation from #temp
where (Year(enddate)=2015 AND Year(enddate)=2015)
AND 8 between MONTH(startdate) AND MONTH(enddate)
group by emp_num
This will work for sqlserver 2012+
DECLARE #t table
(emp_num int, start_date date, end_date date)
INSERT #t values
( 234, '8-2-2015' , '8-5-2015'),
( 234, '6-28-2015', '7-1-2015'),
( 234, '8-29-2015', '9-2-2015'),
( 115, '6-7-2015' , '6-7-2015'),
( 115, '8-7-2015' , '8-10-2015')
DECLARE #date date = '2015-08-01'
SELECT
emp_num,
SUM(DATEDIFF(day,
CASE WHEN #date > start_date THEN #date ELSE start_date END,
CASE WHEN EOMONTH(#date) < end_date
THEN EOMONTH(#date)
ELSE end_date END)+1) [sum]
FROM #t
WHERE
start_date <= EOMONTH(#date)
and end_date >= #date
GROUP BY emp_num
Using a Tally Table:
SQL Fiddle
DECLARE #month INT,
#year INT
SELECT #month = 8, #year = 2015
--SELECT
-- DATEADD(MONTH, #month - 1, DATEADD(YEAR, #year - 1900, 0)) AS start_day,
-- DATEADD(MONTH, #month, DATEADD(YEAR, #year - 1900, 0)) AS end_d
;WITH CteVacation AS(
SELECT
emp_num,
start_date = CONVERT(DATE, start_date, 101),
end_date = CONVERT(DATE, end_date, 101)
FROM vacation
)
,E1(N) AS(
SELECT * FROM(VALUES
(1),(1),(1),(1),(1),(1),(1),(1),(1),(1)
)t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b),
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b),
Tally(N) AS(
SELECT TOP(SELECT MAX(DATEDIFF(DAY, start_date, end_date)) FROM vacation)
ROW_NUMBER() OVER(ORDER BY (SELECT NULL))
FROM E4
)
SELECT
v.emp_num,
COUNT(*)
FROM CteVacation v
CROSS JOIN Tally t
WHERE
DATEADD(DAY, t.N - 1, v.start_date) <= v.end_date
AND DATEADD(DAY, t.N - 1, v.start_date) >= DATEADD(MONTH, #month - 1, DATEADD(YEAR, #year - 1900, 0))
AND DATEADD(DAY, t.N - 1, v.start_date) < DATEADD(MONTH, #month, DATEADD(YEAR, #year - 1900, 0))
GROUP BY v.emp_num
First, you want to use the correct data type to ease your calculation. In my solution, I used a CTE to format your data type. Then build a tally table from 1 up to the max duration of the all the vacations. Using that tally table, do a CROSS JOIN on the vacation table to generate all vacation dates from its start_date up to end_date.
After that, add a WHERE clause to filter dates that falls on the passed month-year parameter.
Here, #month and #year is declared as INT. What you want is to get all dates from the first day of the month-year up to its last day. The formula for first day of the month is:
DATEADD(MONTH, #month - 1, DATEADD(YEAR, #year - 1900, 0))
And for the last day of the month, add one month to the above and just use <:
DATEADD(MONTH, #month, DATEADD(YEAR, #year - 1900, 0))
Some common date routines.
More explanation on tally table.
Select(emp_name,start_date,end_date) AS sum_day from table_Name Group by emp_num,start_date,end_date
Try this
with cte(
Select emp_num,DATEDIFF(day,start_date,end_date) AS sum_day from table_Name
Group by emp_num,start_date,end_date
)
Select emp_num,sum(sum_day) as sum_day from cte group by emp_num

difference between two dates without weekends and holidays Sql query ORACLE

I have 2 tables: the 1st one contains the start date and the end date of a purchase order,
and the 2nd table contains year hollidays
-purchase order
-Holidays
I'm tryign to calculate the number of business days between 2 dates without the weekends and the holidays.
the output should be like this:
Start Date | End Date | Business Days
Could you please help me
You can remove the non-weekend holidays with a query like this:
select (t.end_date - t.start_date) - count(c.date)
from table1 t left join
calendar c
on c.date between t1.start_date and t1.end_date and
to_char(c.date, 'D') not in ('1', '7')
group by t.end_date, t.start_date;
Removing the weekend days is then more complication. Full weeks have two weekend days, so that is easy. So a good approximation is:
select (t.end_date - t.start_date) - (count(c.date) +
2 * floor((t.end_date - t.start_date) / 7))
from table1 t left join
calendar c
on c.date between t1.start_date and t1.end_date and
to_char(c.date, 'D') not in ('1', '7')
group by t.end_date, t.start_date;
This doesn't get the day of week, which is essentially if the end date is before the start date, then it is in the following week. However, this logic gets rather complicated the way that Oracle handles day of the week, so perhaps the above approximation is sufficient.
EDIT: I ignored the presence of the Oracle tag and jumped into scripting this for SQL Server. The concept doesn't change though.
To be super accurate, I would create a table whit the following format.
Year int, month int, DaysInMonth int, firstOccuranceOfSunday int
Create a Procedure to extract the weekends from a specific year and month on that table.
CREATE FUNCTION [dbo].[GetWeekendsForMonthYear]
(
#year int,
#month int
)
RETURNS #weekends TABLE
(
[Weekend] date
)
AS
BEGIN
declare #firstsunday int = 0
Declare #DaysInMonth int = 0
Select #DaysInMonth = DaysInMonth, #firstsunday = FirstSunday from Months
Where [Year] = #year and [month] = #month
Declare #FirstSaterday int = #firstsunday - 1
declare #CurrentDay int = 0
Declare #CurrentDayIsSunday bit = 0
if #FirstSaterday !< 1
Begin
insert into #Weekends values(DATEADD(year, #year -1900, DATEADD(month, #month -1, DATEADD(day, #Firstsaterday -1, 0))))
insert into #Weekends values(DATEADD(year, #year -1900, DATEADD(month, #month -1, DATEADD(day, #FirstSunday -1, 0))))
set #CurrentDayIsSunday = 1
set #CurrentDay = #firstsunday
END
else
begin
insert into #Weekends values(DATEADD(year, #year -1900, DATEADD(month, #month -1, DATEADD(day, #FirstSunday -1, 0))))
set #FirstSaterday = #firstsunday + 6
insert into #Weekends values(DATEADD(year, #year -1900, DATEADD(month, #month -1, DATEADD(day, #Firstsaterday -1, 0))))
set #CurrentDayIsSunday = 0
set #CurrentDay = #FirstSaterday
end
declare #done bit = 0
while #done = 0
Begin
if #CurrentDay <= #DaysInMonth
Begin
If #CurrentDayIsSunday = 1
begin
set #CurrentDay = #CurrentDay + 6
set #CurrentDayIsSunday = 0
if #CurrentDay <= #DaysInMonth
begin
insert into #Weekends Values(DATEADD(year, #year -1900, DATEADD(month, #month -1, DATEADD(day, #CurrentDay -1, 0))))
end
end
else
begin
set #CurrentDay = #CurrentDay + 1
set #CurrentDayIsSunday = 1
if #CurrentDay <= #DaysInMonth
begin
insert into #Weekends Values(DATEADD(year, #year -1900, DATEADD(month, #month -1, DATEADD(day, #CurrentDay -1, 0))))
end
end
end
ELSE
begin
Set #done = 1
end
end
RETURN
END
When called and provided with a year and month this will return a list of dates that represent weekends.
Now, using that function, create a procedure to call this function once for every applicable row in a specific date rang and return the values in a temptable.
Note, I'm posting this now so you can see what's going on but I am continuing to work on the code. I will post updates as they arise.
More to come: Get list of weekends(formatted) for a specific daterange, remove any dates from that list which can be found on your holidays table.
Unfortunately, I have to work tomorrow and am off to bed.
This query should produce exact number of business days for each range in purchase table:
with days as (
select rn, sd + level - 1 dt, sd, ed
from (select row_number() over (order by start_date) rn,
start_date sd, end_date ed from purchase_order)
connect by prior rn = rn and sd + level - 1 <= ed
and prior dbms_random.value is not null)
select sd start_date, ed end_date, count(1) business_days
from days d left join holidays h on holiday_date = d.dt
where dt - trunc(dt, 'iw') not in (5, 6) and h.holiday_date is null
group by rn, sd, ed
SQLFiddle demo
For each row in purchase_orders query generates dates from this range (this is done by subquery dates).
Main query checks if this is weekend day or holiday day and counts rest of dates.
Hierarchical query used to generate dates may cause slowdowns if there is big number of data in purchase_orders
or periods are long. In this case preferred way is to create calendar table, as already suggested in comments.
Since you already have a table of holidays you can count the holidays between the starting and ending date and subtract that from the difference in days between your ending and starting date. For the weekends, you either need a table containing weekend days similar to your table of holidays, or you can generate them as below.
with sample_data(id, start_date, end_date) as (
select 1, date '2015-03-06', date '2015-03-7' from dual union all
select 2, date '2015-03-07', date '2015-03-8' from dual union all
select 3, date '2015-03-08', date '2015-03-9' from dual union all
select 4, date '2015-02-07', date '2015-06-26' from dual union all
select 5, date '2015-04-17', date '2015-08-16' from dual
)
, holidays(holiday) as (
select date '2015-01-01' from dual union all -- New Years
select date '2015-01-19' from dual union all -- MLK Day
select date '2015-02-16' from dual union all -- Presidents Day
select date '2015-05-25' from dual union all -- Memorial Day
select date '2015-04-03' from dual union all -- Independence Day (Observed)
select date '2015-09-07' from dual union all -- Labor Day
select date '2015-11-11' from dual union all -- Veterans Day
select date '2015-11-26' from dual union all -- Thanks Giving
select date '2015-11-27' from dual union all -- Black Friday
select date '2015-12-25' from dual -- Christmas
)
-- If your calendar table doesn't already hold weekends you can generate
-- the weekends with these next two subfactored queries (common table Expressions)
, firstweekend(weekend, end_date) as (
select next_day(min(start_date),'saturday'), max(end_date) from sample_data
union all
select next_day(min(start_date),'sunday'), max(end_date) from sample_data
)
, weekends(weekend, last_end_date) as (
select weekend, end_date from firstweekend
union all
select weekend + 7, last_end_date from weekends where weekend+7 <= last_end_date
)
-- if not already in the same table combine distinct weekend an holiday days
-- to prevent double counting (in case a holiday is also a weekend).
, days_off(day_off) as (
select weekend from weekends
union
select holiday from holidays
)
select id
, start_date
, end_date
, end_date - start_date + 1
- (select count(*) from days_off where day_off between start_date and end_date) business_days
from sample_data;
ID START_DATE END_DATE BUSINESS_DAYS
---------- ----------- ----------- -------------
1 06-MAR-2015 07-MAR-2015 1
2 07-MAR-2015 08-MAR-2015 0
3 08-MAR-2015 09-MAR-2015 1
4 07-FEB-2015 26-JUN-2015 98
5 17-APR-2015 16-AUG-2015 85

Sales counts by week for individual items sold

I have a large SQL table that contains, among other fields, the following
Item, Date Sold,
1 Day Coaster 2014-11-10,
3 Day Coaster 2014-02-16,
1 Day Coaster 2014-11-11,
AC-Zip 2014-12-21,
5 Day Package 2014-05-15,
1 Day Coaster 2014-11-07,
Being new to SQL, my expertise can only select the items individually and take the counts from individual results and type them into excel from the rows affected result.
I need to be able to pull the count of individual items sold by week and list the counts by week into an excel spreadsheet thus;
Week Item Count
2014-11-07-2014-11-13 1 Day Coaster 3
You need to use a Group BY statement.
here is a sample SQLFiddle, it might get you started: SQL Fiddle
You can use this :
SELECT A.Item,A.DateRange,COUNT(A.Item)
FROM (
SELECT Item,
(SELECT DISTINCT
CASE
WHEN YEAR(DATEADD(DAY, 1-DATEPART(WEEKDAY, Min(Date_Sold)), Min(Date_Sold))) < YEAR(Min(Date_Sold))
THEN
CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0,DATEADD(YEAR, 0 ,GETDATE())), 0) AS Varchar(50))
+ ' TO ' + Cast(DATEADD(dd, 7-(DATEPART(dw, Min(Date_Sold))), Min(Date_Sold)) AS Varchar(50))
ELSE
Cast(DATEADD(DAY, 1-DATEPART(WEEKDAY, Min(Date_Sold)), Min(Date_Sold)) AS Varchar(50))
+ ' TO ' + Cast(DATEADD(dd, 7-(DATEPART(dw, Min(Date_Sold))), Min(Date_Sold)) AS Varchar(50))
END AS DateRange
FROM <YOUR_TABLE> B
WHERE A.Date_Sold=B.Date_Sold
AND A.Item=B.Item
group by Item
) AS DateRange
FROM <YOUR_TABLE> A
) A
GROUP BY Item,DateRange;
Let me know if this is not what you are looking at.
USe this. Fiddler Demo
Output:
Query
CREATE TABLE weekdays
(
datevalue datetime NOT NULL
, Item VARCHAR(MAX)
);
INSERT INTO weekdays (datevalue, item) VALUES
('2014-11-10', '1 Day Coaster'),
('2014-02-16', '2 Day Coaster'),
('2014-11-11', '1 Day Coaster'),
('2014-12-21', 'AC-Zip'),
('2014-05-15', '5 Day Package'),
('2014-11-07', '1 Day Coaster');
CREATE FUNCTION [dbo].[ufn_GetFirstDayOfWeek]
( #pInputDate DATETIME )
RETURNS DATETIME
BEGIN
SET #pInputDate = CONVERT(VARCHAR(10), #pInputDate, 111)
RETURN DATEADD(DD, 1 - DATEPART(DW, #pInputDate),
#pInputDate)
END
GO
SET DATEFIRST 5
SELECT CONVERT(VARCHAR(10), A.Date, 101) + ' - ' +
CONVERT(VARCHAR(10), DATEADD(d, 6, A.Date), 101) AS Week,
A.Item,
COUNT(A.Item) AS COUNT FROM
(SELECT [dbo].ufn_GetFirstDayOfWeek(datevalue) AS Date, item FROM weekdays) AS A
GROUP BY A.Date, A.Item