Determining whether date in one table falls between dates in another table - reporting-services

I have two columns of dates, the first column is the date a purchase order was received to be inspected, the second is the date that purchase order was accepted or rejected. What I would like is a graph with dates on the X-axis, and then the number of purchase orders in the queue on that day on the Y-axis.
Some purchase orders are completed that day, so they would still be counted, but they might not get addressed for days or weeks, so they would be counted on all those days until they were addressed.
Sample data below:
Row ID Date In Date Out
1 9/1/18 9/1/18
2 9/1/18 9/1/18
3 9/1/18 9/2/18
4 9/1/18 9/3/18
1 9/2/18 9/2/18
2 9/2/18 9/4/18
So, it would be 4 for 9/1/18, 4 for 9/2/18, 2 for 9/3/18, and 1 for 9/4/18.
I asked a similar question for Excel, and had success with that. However, we would like the data to be generated from within our ERP system (as opposed to copying the data to Excel manually), and I thought this might be possible using SQL and SSRS.
The formula for Excel was =COUNTIFS($A$1:$A$1000,"<="&C1,Sheet1!$B$1:$B$1000,">="&C1), so A and B were the Date In and Date Out columns, respectively, and then C was a column of all the days for the year.
I am not sure how I would a query like this, so I've started by making it similar to the Excel solution. I generated a list of dates, and I am trying to compare a date in that list to my dataset of purchase order dates, but I'm not sure how to do that, since it's comparing one (row by row) to many.

You need to create a table of dates and then join it to your orders based on the date being between the Date In and Date Out so that they are counted in multiple days.
DECLARE #START_DATE AS DATE = '2018-09-01'
DECLARE #END_DATE AS DATE = '2018-09-30'
IF OBJECT_ID('tempdb..#DATES') IS NOT NULL DROP TABLE #DATES;
IF OBJECT_ID('tempdb..#ORDERS') IS NOT NULL DROP TABLE #ORDERS;
SELECT 1 AS ROW_ID, CAST('2018-09-01' AS DATE) AS DATE_IN, CAST('2018-09-01' AS DATE) AS DATE_OUT
INTO #ORDERS
UNION
SELECT 2 AS ROW_ID, CAST('2018-09-01' AS DATE) AS DATE_IN, CAST('2018-09-01' AS DATE) AS DATE_OUT
UNION
SELECT 3 AS ROW_ID, CAST('2018-09-01' AS DATE) AS DATE_IN, CAST('2018-09-02' AS DATE) AS DATE_OUT
UNION
SELECT 4 AS ROW_ID, CAST('2018-09-01' AS DATE) AS DATE_IN, CAST('2018-09-03' AS DATE) AS DATE_OUT
UNION
SELECT 1 AS ROW_ID, CAST('2018-09-02' AS DATE) AS DATE_IN, CAST('2018-09-02' AS DATE) AS DATE_OUT
UNION
SELECT 2 AS ROW_ID, CAST('2018-09-02' AS DATE) AS DATE_IN, CAST('2018-09-04' AS DATE) AS DATE_OUT
;WITH GETDATES AS (SELECT #START_DATE AS DATE1
UNION ALL
SELECT DATEADD(DAY, 1, DATE1)
FROM GETDATES
WHERE DATE1 < #END_DATE
)
SELECT *
INTO #DATES
FROM GETDATES;
SELECT DATE1, COUNT(O.ROW_ID) AS ORDERS
FROM #DATES D
LEFT JOIN #ORDERS O ON D.DATE1 BETWEEN O.DATE_IN AND O.DATE_OUT
GROUP BY D.DATE1

Try comparing using "ReportItems!" property. Try to write expression something like:
iif(ReportItems!DateColumnX = somevalue, "Then Do something", "Else Do Something else")
Edits:
Try something like this:
Fields!ValueFromCurrentDataset(CompareLogic like(<,>,<> etc)) LookUp( Fields!ValueFromDataset2, "DataSet2")

Related

How do I select SQL data in buckets when data doesn't exist for one bucket?

I'm trying to get a complete set of buckets for a given dataset, even if no records exist for some buckets.
For example, I want to display totals by day of week, with zero total for days with no records.
SELECT
WEEKDAY(transaction_date) AS day_of_week,
SUM(sales) AS total_sales
FROM table1
GROUP BY day_of_week
If I have sales every day, I'll get 7 rows in my result representing total sales on days 0-6.
If I don't have sales on Day 2, I get no result for Day 2.
What's the most efficient way to force a zero value for day 2?
Should I join to a temporary table or array of defined buckets? ['0','1','2','3','4','5','6']
Or is it better to insert zeros outside of MySQL, after I've done the query?
I am using MySQL, but this is a general SQL question.
In MySQL, you could simply use a derived table of numbers from 1 to 7, left join it with the table, then aggregate:
select d.day_of_week, sum(sales) AS total_sales
from (
select 1 day_of_week union all select 2 union all select 3 union all select 4
union all select 5 union all select 6 union all select 7
) d
left join table1 t1 on weekday(t1.transaction_date) = d.day_of_week
group by day_of_week
Very recent versions have the values(row...) syntax, which shortens the query:
select d.day_of_week, sum(sales) AS total_sales
from (values row(1), row(2), row(3), row(4), row(5), row(6), row(7)) d(day_of_week)
left join table1 t1 on weekday(t1.transaction_date) = d.day_of_week
group by day_of_week
Basically you want the answer to be 0 when the data is actually null for that bucket, therefore you want the max(null, 0). A max function wouldn't natively work with NULL in this way, however, you can use COALESCE to force it:
COALESCE(MAX(SUM(sales)),0)
as suggested by this answer
First off you need a calendar table; something like this or this. Or create calendar subset on the fly. I am not sure of the mySQL syntax, but here is what it would look like in SQL Server.
DECLARE
#FromDate DATE
, #ToDate DATE
-- set these variables to appropriate values
SET #FromDate = '2020-03-01';
SET #ToDate = '2020-03-31';
;WITH cteCalendar (MyDate) AS
(
SELECT CONVERT(DATE, #FromDate) AS MyDate
UNION ALL
SELECT DATEADD(DAY, 1, MyDate)
FROM cteCalendar
WHERE DATEADD(DAY, 1, MyDate) <= #ToDate
)
SELECT WEEKDAY(cte.MyDate) AS day_of_week,
SUM(sales) AS total_sales
FROM cteCalendar cte
LEFT JOIN table1 t1 ON cte.MyDate = t1.transaction_date
GROUP BY day_of_week

SQL: Count/ sum columns within a specific date range

I have a table that roughly looks like this. There are thousands of rows.
booking_date checkin_date ...some other columns .... booking_value
22-mar-2016 29-mar-2016 ........................... $150
01-apr-2016 17-may-2016 ........................... $500
09-apr-2016 09-apr-2016 ........................... $222
17-apr-2016 23-apr-2016 ........................... $75
19-apr-2016 31-july-2016 ........................... $690
03-May-2016 07-May-2016 ............................. $301
.
.
.
.
I am trying to calculate number of bookings per day and the value of bookings per day in April 2016. The second part is to calculate for how many bookings the booking_date and checking_date were the same.
I am very new to SQL. I can formulate the logic in paper, but can't seem to figure out how to proceed with the code.
I recommend the following query:
SELECT CAST(booking_date AS DATE), COUNT(*) as Number_of_Booking,
SUM(CAST(booking_date AS DATE) = CAST(checkin_date AS DATE)) as count_with_same_date,
SUM(booking_value) as booking_value
FROM t
WHERE booking_date >= '2016-04-01' AND
booking_date < '2016-05-01'
GROUP BY CAST(booking_date AS DATE);
In particular, note the filtering on the dates. The direct comparisons allow MySQL to use an index.
The calculation of the number on the same date uses a nice feature of MySQL where boolean values are treated as numbers in a numeric context.
You can try this below code-
SELECT CAST(booking_date AS DATE),
COUNT(*) Number_of_Booking,
COUNT(
CASE
WHEN CAST(booking_date AS DATE)
= CAST(checkin_date AS DATE) THEN 1
ELSE NULL
END
) count_with_same_date,
SUM(booking_value) booking_value -- Booking value has to be Number field
FROM your_table
WHERE YEAR(booking_date ) = 2016
AND MONTH(booking_date ) = 4
GROUP BY CAST(booking_date AS DATE)
For the first question you can try
Select booking_date
,count(*) as Number_of_bookings
,Sum(booking_value) as value
From table_name
Where booking_date between '01-apr-2016' and '30-apr-2016'
group by booking_date:
Or you can use month() and year() function in filter.
For the second question try,
Select booking_date
,checkin_date
,count(*)
from table_name
where booking_date=checkin_date
group by booking_date, checkin_date

How do I retrieve all records between a date range and then filtered by time of day?

My dateTime column has entries like this going back months:
2019-03-11 07:00:00.000
I would like to retrieve all the data from mondays, but then further filtered by the time of day.
This is what I have so far but I dont know how to refine it any further.
WITH
cteMonday (dates1, Average) AS
(
select [Date], [High] - [Low] AS 'average'
--select *
from [Trading].[dbo].[DAX30m]
where DATEPART(dw, Date) = 2
AND [DATE] BETWEEN '2019-03-11' AND '2019-03-24'
)
select * from ctemonday
Why don't you use the DATEPART function to extend your filter criteria, e.g.:
... AND DATEPART(hh, Date) > lowerLimit AND DATEPART(hh, Date) <
upperLimit

Find number of "active" rows each month for multiple months in one query

I have a mySQL database with each row containing an activate and a deactivate date. This refers to the period of time when the object the row represents was active.
activate deactivate id
2015-03-01 2015-05-10 1
2013-02-04 2014-08-23 2
I want to find the number of rows that were active at any time during each month. Ex.
Jan: 4
Feb: 2
Mar: 1
etc...
I figured out how to do this for a single month, but I'm struggling with how to do it for all 12 months in a year in a single query. The reason I would like it in a single query is for performance, as information is used immediately and caching wouldn't make sense in this scenario. Here's the code I have for a month at a time. It checks if the activate date comes before the end of the month in question and that the deactivate date was not before the beginning of the period in question.
SELECT * from tblName WHERE activate <= DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND deactivate >= DATE_SUB(NOW(), INTERVAL 2 MONTH)
If anybody has any idea how to change this and do grouping such that I can do this for an indefinite number of months I'd appreciate it. I'm at a loss as to how to group.
If you have a table of months that you care about, you can do:
select m.*,
(select count(*)
from table t
where t.activate_date <= m.month_end and
t.deactivate_date >= m.month_start
) as Actives
from months m;
If you don't have such a table handy, you can create one on the fly:
select m.*,
(select count(*)
from table t
where t.activate_date <= m.month_end and
t.deactivate_date >= m.month_start
) as Actives
from (select date('2015-01-01') as month_start, date('2015-01-31') as month_end union all
select date('2015-02-01') as month_start, date('2015-02-28') as month_end union all
select date('2015-03-01') as month_start, date('2015-03-31') as month_end union all
select date('2015-04-01') as month_start, date('2015-04-30') as month_end
) m;
EDIT:
A potentially faster way is to calculate a cumulative sum of activations and deactivations and then take the maximum per month:
select year(date), month(date), max(cumes)
from (select d, (#s := #s + inc) as cumes
from (select activate_date as d, 1 as inc from table t union all
select deactivate_date, -1 as inc from table t
) t cross join
(select #s := 0) param
order by d
) s
group by year(date), month(date);

MySQL generating monthly breakdown from date ranges

good morning,
I have a nagging issue I cannot really solve.. I have a database table like this, showing resources spent (value) in a date range by person:
id,name,startdate,enddate,value
--------------------------------
10,John,2012-01-14,2012-10-30,200000
11,Jack,2012-02-01,2012-08-01,70000
12,John,2012-05-01,2012-06-01,2000
I need a query that creates the result like this, summarizing the 'value' by month, taking partial months into account
month, name, value
------------------
2012-01, John, 9000
2012-02, John, 18000
2012-03, John, 18000
2012-04, John, 18000
2012-05, John, 20000
2012-06, John, 18000
2012-07, John, 18000
2012-08, John, 18000
2012-01, John, 18000
2012-02, Jack, 10000
2012-03, Jack, 10000
2012-04, Jack, 10000
2012-05, Jack, 10000
2012-06, Jack, 10000
2012-07, Jack, 10000
2012-08, Jack, 0
Now I know how I'd do this procedurally (like with PHP) with a loop: get the daily amount, then check month by month how many days spent there according to the range and multiply it by the daily amount.
thanks
peter
If you don't have a calendar table and can't create one, you can simulate a virtual calendar table in your query. Here's a query that should answer your question, that makes use of such a virtual table:
select m.startmonth,
e.name,
coalesce(sum(r.value *
datediff(case when adddate(m.startmonth, interval 1 month) <
r.enddate
then adddate(m.startmonth, interval 1 month)
else r.enddate end,
case when m.startmonth > r.startdate
then m.startmonth else r.startdate end) /
datediff(r.enddate,r.startdate)),0) valueshare
from
(select cast('2012-01-01' as date) startmonth union all
select cast('2012-02-01' as date) startmonth union all
select cast('2012-03-01' as date) startmonth union all
select cast('2012-04-01' as date) startmonth union all
select cast('2012-05-01' as date) startmonth union all
select cast('2012-06-01' as date) startmonth union all
select cast('2012-07-01' as date) startmonth union all
select cast('2012-08-01' as date) startmonth union all
select cast('2012-09-01' as date) startmonth union all
select cast('2012-10-01' as date) startmonth) m
cross join employees e
left join resources_spent r
on r.enddate > m.startmonth and
r.startdate < adddate(m.startmonth, interval 1 month) and
r.name = e.name
group by m.startmonth, e.name
order by 2,1
SQLFiddle here.
I think you need a calendar table with one row for each date. Other fields would be whatever is useful to you, such as fiscal periods, holidays, whatever.
Then, for your report, you could create a temp table and populate it like this:
insert into YourTempTable
(id, date, amount)
select id, c.datefield, amount
from YourTable join Calendar c on datefield >= startdate
and datefield <= enddate
where whatever
From there, you select from YourTempTable and YourTable, joining on the id.