SQL update based on query results with two parameters - sql-server

I've created a virtual table in SQL Server that has 28 days from the current date and each date has rows for time that range from 12-10 pm incremented by 15 min and another value to indicate that it's turned on/off for availability, so it would be something like this:
date time onoff
-------------------------------------------------
2015-04-08 12:00 1
2015-04-08 12:15 1
....continue until 22:00 then start next day
2015-04-09 12:00 1
..... continue for 28 days
I'd like to update the availability based on a query from another table which would return the date, start and end time...
So far I came up with this
update table1
set onoff = 0
where tbl1date in (select tbl2date from table2 where userid = 1)
The problem I'm having is adding in the between certain hours part of the equation and I'm not sure how to do something like this in SQL or how to even search for the answer based on not being able to word it properly...
Can someone help or point me in the right direction?

use a DATETIME, don't use separate DATE and TIME fields.

I think you should take a look at DATEDIFF (https://technet.microsoft.com/pl-pl/library/ms189794(v=sql.110).aspx) function.
Your where query could look like this:
update table1 set onoff = 0
where
DATEDIFF(minute, <MIN_RANGE>, tbl1date) >= 0 and
DATEDIFF(minute, tbl1date, <MAX_RANGE>) >= 0
How you calculate MIN_RANGE and MAX_RANGE depends on your table2 structure.

As suggested, if you have control over the structure, use datetime fields as they are easier to do the comparisons on. I'm going to assume you don't have control over the structure.
In order to compare the datetimes you need to create them from your separate date and times. You can either parse the time field for the hours and minutes and use DATEADD to add the appropriate offsets to the date, or you can use CONVERT to interpret a date time string as a date. Something like
CONVERT(datetime, SUBSTRING(CONVERT(varchar, tbl1date, 121), 1, 10) + ' ' + tbl1time, 121)
What this does is to convert the date to odbc cannonical format and throwaway the time part as it takes only the first 10 characters. Then it appends the time and interprets the whole string as a odbc cannonical datetime string. That format is yyyy-mm-dd hh:mi:ss.mmm. The hours are based on 24 hours. So if your times are in AM/PM format you're going to have to convert them.
If your other table has separate date and times you'd use a similar expression to combine them.
Once you have the datetimes you can do something like this
UPDATE table1
SET onoff = 0
WHERE <expression above> BETWEEN (SELECT min_value FROM table2) AND (SELECT max_value FROM table2)

Related

How do I use GETDATE in a WHERE clause using single quotes?

How do I use GETDATE() in a WHERE clause using single quotes? I have the following script:
SELECT DISTINCT
pm_requisition.a_requisition
,pm_requisition.a_req_description
,pm_requisition.rq_position_loc
,pm_requisition.rq_status_of_emp
,pm_applicant_rec.a_applicant_no
,pm_applicant_rec.aq_status_of_appl
,pm_applicant_rec.aq_apply_date
FROM
pm_requisition
LEFT OUTER JOIN pm_applicant_rec
ON pm_requisition.a_requisition = pm_applicant_rec.a_requisition
WHERE
pm_requisition.rq_status_of_req NOT IN (N'6', N'7')
AND pm_applicant_rec.aq_status_of_appl = N'N'
AND rq_position_loc = '3300'
AND pm_applicant_rec.aq_apply_date = CAST(GETDATE()AS datetime2) --('2021-03-30 00:00:00.000')
The dataset does not yield any data using the GETDATE() clause, but if I use today's date (commented out) with single quotes I get the correct dataset. I obviously can't put single quotes around CAST(GETDATE()AS datetime2). Am I missing something simple?
The reason your query does not work is that GETDATE() returns the current date and time, not the current date. As a result, the last line will never match, as you are comparing a date only with a date and time.
Your solution CAST(GETDATE() AS DATE) works is because it removes the time, which means you are now comparing a date with a date.
If you simplify your SQL to something like this :-
SELECT TOP 1 aq_apply_date,
GETDATE() [GETDATE]
FROM pm_applicant_rec;
you will see a result like this, so two different values, and clear why they do not match :-
aq_apply_date GETDATE
----------------------- -----------------------
2021-04-04 00:00:00.000 2021-04-04 14:32:15.507
You might see something slightly different depending on the datatype used for aq_apply_date.

How to use stored procedure to calculate DateTime difference in hours?

I have two tables, TicketReport and TimeTracker.
TicketReport Columns:
Ticket_Number
Report_DT (DateTime ticket was reported)
Response_Time (Hourly value. How long it took for this ticket to be responded to. This is where I need the place the hours. DateTime Reported minus DateTime started)
TimeTracker Column:
Ticket_Number
Time_Start( DateTime that work started on this ticket)
Right now, for every row in my TicketReport table, the Response_Time column contains either Null or just a test value of 1(hour).
*I need to calculate how many hours it took for a ticket to be responded to (ReportDT - Time_Start), and then insert that hourly value into the Report_DT column for each row in the TicketReport table.
I did some research and found DATEDIFF, but I think this only returns days, and even if it did return hours, im not sure how to use it.
How could I accomplish this in a stored procedure?
To update the response_time column with the number of hours you can use a simple update query (which you could wrap in a stored proc if you need.
The query could look like this:
-- uncomment the next line to create a sp...
-- create proc update_response_time as
update tr
set response_time = datediff(hour, report_dt, time_start)
from TicketReport tr
join TimeTracker tt on tr.Ticket_Number = tt.Ticket_Number
If you want to run it without updating (to see what the values would be) you can run it as a select query:
select *, datediff(hour, report_dt, time_start) as diff_in_hours
from TicketReport tr
join TimeTracker tt on tr.Ticket_Number = tt.Ticket_Number
Be aware that these queries assume that there are just one matching row in the TimeTracker table for each ticket. If there can be multiple rows you would need another solution. Also know that the hour value doesn't take minutes into account at all so if report_dt is at 12:00 and time_start is at 12:30 it would be reported as 0 hours, so maybe a finer granularity than hours would be more suitable.
You can use DATEDIFF function
Syntax
DATEDIFF ( datepart , startdate , enddate )
pass datepart hh to get hours

SQL Server Stored Procedure get nearest available date to parameter

I have a table of database size information. The data is collected daily. However, some days are missed due to various reasons. Additionally we have databases which come and go over or the size does not get recorded for several databases for a day or two. This all leads to very inconsistent data collection regarding dates. I want to construct a SQL procedure which will generate a percentage of change between any two dates (1 week, monthly, quarterly, etc.) for ALL databases The problem is what to do if a chosen date is missing (no rows for that date or no row for one or more databases for that date). What I want to be able to do is get the nearest available date for each database for the two dates (begin and end).
For instance, if database Mydb has these recording dates:
2015-05-03
2015-05-04
2015-05-05
2015-05-08
2015-05-09
2015-05-10
2015-05-11
2015-05-12
2015-05-14
and I want to compare 2015-05-06 with 2015-05-14
The 2015-05-07 date is missing so I would want to use the next available date which is 2015-05-08. Keep in mind, MyOtherDB may only be missing the 2015-05-06 date but have available the 2015-05-07 date. So, for MyOtherDb I would be using 2015-05-07 for my comparison.
Is there a way to proceduralize this with SQL WITHOUT using a CURSOR?
You're thinking too much into this, simple do a "BETWEEN" function in your where clause that takes the two parameters.
In your example, if you perform the query:
SELECT * FROM DATABASE_AUDIT WHERE DATE BETWEEN param1 /*2015-05-06*/ and param2 /*2015-05-14*/
It will give you the desired results.
select (b.dbsize - a.dbsize ) / a.dbsize *100 dbSizecChangePercent from
( select top 1 * from dbAudit where auditDate = (select min(auditDate) from dbAudit where auditDate between '01/01/2015' and '01/07/2015')) a
cross join
(select top 1 * from dbAudit where auditDate = (select max(auditDate) from dbAudit where auditDate between '01/01/2015' and '01/07/2015')) b
The top 1 can be replaced by a group by. This was assuming only 1 db aduit per day

SQL server 2005 - query aribitrary time interval in date range

I have a DateTime column. I want to extract all records, lets say, from 8:30 to 16:15 within a certain date range. My problem is that I need to compare hour and minute as a single time value. I can test the DATEPART for Greater or Less than some hours value, but if I then do that for minutes my query will fail if the later-in-the-day time has a smaller minutes value.
I have looked at INTERVAL, BETWEEN, DATEPART, DATEDIFF etc, but don't see quite how to to this without a "TimeOfDay" value that I can use across records of different dates.
I have tried subtracting the year, month and day parts of the date so that I can compare just the time of day, but when attmpting to subract, say, the year part of a date I get an overlfow error:
This part works:
select - cast( DATEPART(YEAR, CallTime) as integer) from history
This fails:
select DATEADD(YEAR, - cast( DATEPART(YEAR, CallTime) as integer), CallTime)
from history where calltime is not null
I have also tried casting the hours and minutes parts to chars, concatenating them and comparing to my target range, but this also fails.
I believe newer versions of SQL server may have a function to deal with this situation, but that's not available to me.
I hope and imagine there is a simple, obvious solution to this, but it's eluding me.
Try creating a "MinuteOfDay" function that calculates how many minutes have passed in the day based on a datetime.
CREATE FUNCTION dbo.[MinuteOfDay]
(
#dt datetime
)
RETURNS int
AS
BEGIN
RETURN (datepart(hh,#dt)*60) + datepart(mi,#dt)
END
then use the result of that function to filter.
select *
from MyTable t
where dbo.MinuteOfDay(t.SomeDateTimeColumn) between dbo.MinuteOfDay('1900-1-1 08:30:00') and dbo.MinuteOfDay('1900-1-1 16:15:00')
give this a shot:
DECLARE #StartDateTime datetime
,#EndDateTime datetime
--date range is ALL of January 1st up to & including 31st
SELECT #StartDateTime='2011/01/01'
,#EndDateTime='2011/01/31'
SELECT
*
FROM TableName t
WHERE
t.ColumnDate>=#StartDateTime AND t.ColumnDate<#EndDateTime+1 --date range
AND LEFT(RIGHT(CONVERT(char(19),t.ColumnDate(),120),8),5)>='08:30' --time range start
AND LEFT(RIGHT(CONVERT(char(19),t.ColumnDate(),120),8),5)<='16:15' --time range end
if you have an index on t.ColumnDate, this should be able to take advantage of it.
the "date range" part of the WHERE throws away rows that are not within the intended date range. The "time range start" part of the WHERE throws away rows that are to early in time and the "time range end" throws away rows that are to late.
DATETIME values can be cast as FLOAT. Actually, a DATETIME is stored as a FLOAT.
The whole part of the FLOAT is the days since '12/31/1899' (or something close). The fractional part is the number of hours divided by 24. So 0.5 = 12 Noon.
08:30 is 0.3541666667
16:15 is 0.6770833333
SELECT CAST(CAST('2011-03-25 08:30:00' AS DATETIME) AS FLOAT) = 40625.3541666667
SELECT CAST(CAST('2011-03-25 16:15:00' AS DATETIME) AS FLOAT) = 40625.6770833333
So you could write
SELECT * FROM users WHERE hire_date < 40625.3541666667
Using a DATETIME as FLOAT you can use whichever mathematical functions work best for your query.

SQL Server Retrieving Recurring Appointments By Date

I'm working on a system to store appointments and recurring appointments. My schema looks like this
Appointment
-----------
ID
Start
End
Title
RecurringType
RecurringEnd
RecurringTypes
---------------
Id
Name
I've keeped the Recurring Types simple and only support
Week Days,
Weekly,
4 Weekly,
52 Weekly
If RecurringType is null then that appointment does not recur, RecurringEnd is also nullable and if its null but RecurringType is a value then it will recur indefinatly. I'm trying to write a stored procedure to return all appointments and their dates for a given date range.
I've got the stored procedure working for non recurring meetings but am struggling to work out the best way to return the recurrences this is what I have so far
ALTER PROCEDURE GetAppointments
(
#StartDate DATETIME,
#EndDate DATETIME
)
AS
SELECT
appointment.id,
appointment.title,
appointment.recurringType,
appointment.recurringEnd,
appointment.start,
appointment.[end]
FROM
mrm_booking
WHERE
(
Start >= #StartDate AND
[End] <= #EndDate
)
I now need to add in the where clauses to also pick up the recurrences and alter what is returned in the select to return the Start and End Dates for normal meetings and the calculated start/end dates for the recurrences.
Any pointers on the best way to handle this would be great. I'm using SQL Server 2005
you need to store the recurring dates as each individual row in the schedule. that is, you need to expand the recurring dates on the initial save. Without doing this it is impossible to (or extremely difficult) to expand them on the fly when you need to see them, check for conflicts, etc. this will make all appointments work the same, since they will all actually have a row in the table to load, etc. I would suggest that when a user specifies their recurring date, you make them pick an actual number of recurring occurrences. When you go to save that recurring appointment, expand them all out as individual rows in the table. You could use a FK to a parent appointment row and link them like a linked list:
Appointment
-----------
ID
Start
End
Title
RecurringParentID FK to ID
sample data:
ID .... RecurringParentID
1 .... null
2 .... 1
3 .... 2
4 .... 3
5 .... 4
if in the middle of the recurring appointments schedule run, say ID=3, they decide to cancel them, you can follow the chain and delete the remaining ID=3,4,5.
as for expanding the dates, you could use a CTE, numbers table, while loop, etc. if you need help doing that, just ask. the key is to save them as regular rows in the table so you don't need to expand them on the fly every time you need to display or evaluate them.
I ended up doing this by creating a temp table of everyday between the start and end date along with their respective day of the week. I limited the recurrence intervals to weekdays and a set amount of weeks and added where clauses like this
--Check Week Days Reoccurrence
(
mrm_booking.repeat_type_id = 1 AND
#ValidWeeklyDayOfWeeks.dow IN (1,2,3,4,5)
) OR
--Check Weekly Reoccurrence
(
mrm_booking.repeat_type_id = 2 AND
DATEPART(WEEKDAY, mrm_booking.start_date) = #ValidWeeklyDayOfWeeks.dow
) OR
--Check 4 Weekly Reoccurences
(
mrm_booking.repeat_type_id = 3 AND
DATEDIFF(d,#ValidWeeklyDayOfWeeks.[Date],mrm_booking.start_date) % (7*4) = 0
) OR
--Check 52 Weekly Reoccurences
(
mrm_booking.repeat_type_id = 4 AND
DATEDIFF(d,#ValidWeeklyDayOfWeeks.[Date],mrm_booking.start_date) % (7*52) = 0
)
In case your interested I built up a table of the days between the start and end date using this
INSERT INTO #ValidWeeklyDayOfWeeks
--Get Valid Reoccurence Dates For Week Day Reoccurences
SELECT
DATEADD(d, offset - 1, #StartDate) AS [Date],
DATEPART(WEEKDAY,DATEADD(d, offset - 1, #StartDate)) AS Dow
FROM
(
SELECT ROW_NUMBER() OVER(ORDER BY s1.id) AS offset
FROM syscolumns s1, syscolumns s2
) a WHERE offset <= DATEDIFF(d, #StartDate, DATEADD(d,1,#EndDate))
Its not very elegant and probably very specific to my needs but it does the job I needed it to do.

Resources