Use Max date to create a date range - sql-server-2008

I need to create a date range in a table that houses transaction information. The table updates sporadically throughout the week from a manual process. Each time the table is updated transactions are added up to the previous Sunday. For instance, the upload took place yesterday and so transactions were loaded through last Sunday (Feb 26th). If it had been loaded on Wednesday it would still be dated for Sunday. The point is that I have a moving target with my transactions and also when the data is loaded to the table. I am trying to fix my look back period to the date of the latest transaction then go three weeks back. Here is the query that I came up with:
SELECT distinct TransactionDate
FROM TransactionTABLE TB
inner join (
SELECT distinct top 21 TransactionDate FROM TrasactionTABLE ORDER BY TransactionDate desc
) A on TB.TransactionDate = A.TransactionDate
ORDER BY TB.TransactionDate desc
Technically this code works. The problem that I am running into now is when there were no transactions on a given date, such as bank holidays (in this case Martin Luther King Day), then the query looks back one day too far.
I have tried a few different options including MAX(TransactionDate) but if I use that in a sub-query or CTE then use the new value in a WHERE statement as a reference I only get the max value or the value I subtract that statement by. For instance if I say WHERE TransactionDate >= MAX(TransactionDate)-21 and the max date is Feb 26th then the result is Feb 2nd instead of the range of dates from Feb 2nd through Feb 26th.
IN SUMMARY, what I need is a date range looking three weeks back from the date of the latest transaction date. This is for a daily report so I cannot hardcode the date in. Since I am also using Excel Connections the use of Declare statements is prohibited.
Thank you StackOverflow gurus in advance!

You could use something like this:
;with n as (select n from (values(0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) t(n))
, dates as (
select top (21)
[Date]=convert(date,dateadd(day, row_number() over (order by (select 1))-1
, dateadd(day,-20,(select max(TransactionDate) from t) ) ) )
from n as deka
cross join n as hecto
order by [Date]
)
select Date=convert(varchar(10),dates.date,120) from dates
rextester demo: http://rextester.com/ZFYV25543
returns:
+------------+
| Date |
+------------+
| 2017-02-06 |
| 2017-02-07 |
| 2017-02-08 |
| 2017-02-09 |
| 2017-02-10 |
| 2017-02-11 |
| 2017-02-12 |
| 2017-02-13 |
| 2017-02-14 |
| 2017-02-15 |
| 2017-02-16 |
| 2017-02-17 |
| 2017-02-18 |
| 2017-02-19 |
| 2017-02-20 |
| 2017-02-21 |
| 2017-02-22 |
| 2017-02-23 |
| 2017-02-24 |
| 2017-02-25 |
| 2017-02-26 |
+------------+

I just found this for looking up dates that fall within a given week. The code can be manipulated to change the week start date.
select convert(datetime,dateadd(dd,-datepart(dw,convert(datetime,convert(varchar(10),DateAdd(dd,-1/*this # changes the week start day*/,getdate()),101)))+1/*this # is used to change the week start date*/,
convert(datetime,convert(varchar(10),getdate(),21))))/*also can enter # here to change the week start date*/
I've included a screenshot of the results if you were to include this with a full query. This way you can see how it looks with a range of dates. I did a little manipulation so that the week starts on Monday and references Monday's date.
Since I am only looking back three weeks a simple GETDATE()-21 is sufficient because as the query moves forward through the week it will look back 21 days and pick the Monday at the beginning of the week as my start date.

Related

Show only available time slots in select field

I am working on a booking system where users can book certain services online. I am stuck on finding and displaying available time slots within a specific day. I know the length of the needed time slot is 1 hour and the business hours.
Is there a way to show time slots that has not yet been booked on a certain day and display only the available time slots that is available to be booked in a dropdown select form?
If a customer selects a specific day and clicks "Select Day" then it needs to query the DB and return the results.
My SQL structure is as follows
|id | title | start_time | end_time | booking_date |
| 1 | Name1 | 2022-05-12 08:00:00 | 2022-05-12 09:00:00 | 2022-05-12 |
| 2 | Name2 | 2022-05-12 10:00:00 | 2022-05-12 11:00:00 | 2022-05-12 |
| 3 | Name3 | 2022-05-12 13:00:00 | 2022-05-12 14:00:00 | 2022-05-12 |
| 4 | Name4 | 2022-05-12 14:00:00 | 2022-05-12 15:00:00 | 2022-05-12 |
as per above the select form should display the timeslots that is not already taken.
09:00 - 10:00
12:00 - 13:00
15:00 - 16:00
It would be something like:
select
id, title
from
<table>
where
start_time between '2022-05-12 00:00:00' and '2022-05-12 11:59:59'
and
booking_date is null
I don't know the name of your table, so you would need to replace <table> with that. I'm also assuming that "booking_date" will have a value to indicate that time slot has been reserved, that it's a date field, and it will be null if that slot hasn't been selected. However, booking_date could have a different purpose.
This is a lazy answer
(because I think just use SQL will do it, use subSelect and other function, but I don't know how to do, sorry.)
get today occupy time:
SELECT id, TIME(start_time) AS s_time FROM tablename
WHERE start_time >= '2022-05-12 00:00:00'
AND start_time < '2022-05-13 00:00:00'
diff time in php:
$sqlResult = []; // sql result
$timeAll = [
'00:00:00',
'01:00:00',
'02:00:00',
'03:00:00',
... // TODO: we need fill it
'23:00:00',
];
foreach ($sqlResult as $item) {
if (isset($timeAll[$item['s_time']])) {
unset($timeAll[$item['s_time']]);
}
}
return $timeAll;
// TODO: javascript or other client code can use it.
ref knowledge link:
MySQL SELECT WHERE datetime matches day (and not necessarily time)
If you choose 2022-05-26, and Peter is occupying room F25 from 2022-05-16 until 2022-05-29, it means the date you select must be out of this range.
So, the query below will only return rooms that were not booked on that day.
SELECT b.id, b.room_id as available_room FROM booking as b
WHERE(
unix_timestamp('$mydate')
NOT BETWEEN unix_timestamp(b.start_date)
AND unix_timestamp(b.end_time)
)
AND unix_timestamp(b.end_time) < unix_timestamp('$mydate');
Assuming $mydate is the variable that contains the date selected by the user, the above query will return rooms that will be available in the future on that particular day.

Self Join? Were Staff Who Worked the Previous Week Active 3 Weeks ago - MYSQL

I'm trying to add a column to a production hours dataset that will tell if a provider who worked last week was also working three weeks earlier. The current dataset looks something like this:
RowID | ProviderID | ClientID | DOS | DOS (Week) | Hours
1 | 1111111111 | 22222222 | 11/2/2020 | 11/1/2020 | 2.5
2 | 1111111111 | 33333333 | 11/5/2020 | 11/1/2020 | 1
3 | 1111111111 | 44444444 | 10/13/2020 | 10/11/2020 | 3
I'm trying to get an extra column 'Active 3 Weeks Prior' with y/n or 1/0 for values. For the above table, let's assume the provider started on 10/13/20. The new column would ideally populate like this:
RowID | ProviderID | ClientID | DOS | DOS (Week) | Hours | Active 3 weeks Prior
1 | 1111111111 | 22222222 | 11/2/2020 | 11/1/2020 | 2.5 | Yes
2 | 1111111111 | 33333333 | 11/5/2020 | 11/1/2020 | 1 | Yes
3 | 1111111111 | 44444444 | 10/13/2020 | 10/11/2020 | 3 | No
A couple extra tidbits: our org uses Sunday as the start of the week so DOS (Week) is the Sunday prior to the date of service. From what I've been reading so far, it seems like the solution here is some kind of self join, where the base production records are aggregated into weekly hours and compared with that same providerID's records for DOS (Week) - 21.
The trouble I'm having is: whether I'm on the right track in the first place with the self-join and how I would generate the y/n values based on the success or failure to find a matching value. Also, I suspect that joining based on a concatenate of ProviderID and DOS(Week) might be flawed? This is what I've been playing with so far.
Please let me know if I can clarify the question at all or am missing something very obvious. I truly appreciate any help, as I've been trying to figure out the right search terms to get a clue on the answer for a few days now.
If you are running MySQL 8.0, you can use window functions and a range specification:
select t.*,
(
max(providerid) over(
partition by providerid
order by dos
range between interval 3 week preceding and interval 3 week preceding
) is not null
) as active_3_weeks_before
from mytable t
It is not really clear from your explanation and data what you mean by was also working three weeks earlier. What the query does is, for each row, to check if another row exists with the same supplier and a dos that is exactly 3 week before the dos of the current row. This can easily be adapted for some other requirement.
Edit: if you want to check for any record within the last 3 weeks, you would change the window range to:
range between interval 3 week preceding and interval 1 day preceding
And if you want this in MySQL < 8.0, where window functions are not available, then you would use a correlated subquery:
select t.*,
exists (
select 1
from mytable t1
where
t1.providerid = t.provider_id
and t1.dos >= t.dos - interval 3 week
and t1.dos < t.dos
) as active_3_weeks_before
from mytable t

How can I select the last timestamp reading per day for multiple user id's and multiple days?

I have a database that contains user id, calories burned (value), and the timestamp at which those calories burned were recorded(reading_date). An individual could have multiple calorie readings for the same day, but I'm only interested in the last reading since it's a total of all the previous readings for that day.
IN:
SELECT
DISTINCT ON (date, user_contents.content_id)
date_trunc('day',reading_date + time '05:00') date,
user_id,
created_at,
value
FROM data
OUT:
date | user_id | created_at | value
2019-01-13 00:00:00 | 138 | 2019-01-18 06:07:52 | 81.0
2019-01-15 00:00:00 | 137 | 2019-01-15 15:43:25 | 87.0
2019-01-16T00:00:00 | 137 | 2019-01-18 04:22:11 | 143.0
2019-01-16T00:00:00 | 137 | 2019-01-18 06:12:11 | 230.0
additional values omitted
I want to be able to select the maximum reading value for each day per person. I've tried using DISTINCT statements such as:
SELECT
DISTINCT ON (date, user_contents.content_id)
date_trunc('day',reading_date + time '05:00') date,
Sometimes that results in an error message:
SELECT DISTINCT ON expressions must match initial ORDER BY expressions
Sometimes it filters out some results, but isn't always giving me the last reading of the day or only one result per person per day.
My optimal end result would look like this (the third record having been removed):
date | user_id | created_at | value
2019-01-13 00:00:00 | 138 | 2019-01-18 06:07:52 | 81.0
2019-01-15 00:00:00 | 137 | 2019-01-15 15:43:25 | 87.0
2019-01-16T00:00:00 | 137 | 2019-01-18 06:12:11 | 230.0
additional values omitted
Ultimately, I'm going to use this data to sum up the value column and determine the total number of calories burned by everyone in the dataset over a time period.
You appear to be using Postgres.
Follow the instructions in the error message. You want something like this:
SELECT DISTINCT ON (user_id, reading_date::date)
date_trunc('day',reading_date + time '05:00') date,
user_id, created_at,value
FROM data
ORDER BY user_id, reading_date::date DESC, reading_date DESC

SQL Statement with the actual week

I have a table which look like this:
Date | Day | Ingredients
-------------------------------------------
2014-08-20 | Wednesday | Salt
2014-08-21 | Thursday | Sugar
2014-08-22 | Friday | Salt&Sugar
2014-08-28 | Thursday | Salt
And I want to have only the dates there are in one week. Should I make an extra column 'Week' with the number of the week or is there a solution where I can set the beginning and the end of a week to only have the actual week. So I have all rows from the actual week.
SELECT * FROM table WHERE *`Date is in the actual week`*
You mean to get the data of current week?
Use the YEARWEEK function.
SELECT * FROM your_table
WHERE YEARWEEK(`date`, 1) = YEARWEEK(CURRENT_DATE, 1)
Update:
Use mode 1 if the beginning of week is Monday.

Counting Occurrences of Day Names By Distinct Weeks

Apologies in advance if this question is badly worded!
I have a MySQL table which has a datetime field. How would one count the number of occurrences of each day name, for distinct weeks?
Here is the query I'm trying, and the result it gives from just over 2 weeks of data. It is (obviously) counting every occurrence for each record, whereas I want the output to be either 2 or 3.
SELECT dayname(datetime), COUNT(dayofweek(datetime))
FROM mytable GROUP BY dayofweek(datetime);
+-------------------+----------------------------+
| dayname(datetime) | count(dayofweek(datetime)) |
+-------------------+----------------------------+
| Monday | 404 |
| Tuesday | 275 |
| Wednesday | 251 |
| Thursday | 196 |
| Friday | 201 |
| Saturday | 128 |
+-------------------+----------------------------+
Grouping by week did not solve the problem. I feel as though I need to "count where week is distinct" but I'm not sure if this is possible.
Any guidance is much appreciated, thank you!
Try to count distinct values (date part only) of your datetime field. More about COUNT(DISTINCT expr,[expr...]) and DATE(expr) that returns the date part only from datetime field.
SELECT dayname(datetime), COUNT(distinct date(datetime))
FROM mytable GROUP BY dayname(datetime);
You normally group on what you are not counting.