Sql Query To get data - sql-server-2005

i have a table called DrTimings ,in which Doctors time for each day is this.
DrID(int identity) StartTime(DateTime) EndTime(DateTime)
1 3/31/2009 8:00:00 AM 3/31/2009 10:30:00 AM
I have another table called TimeList which contain 3 fields
SlotID SlotStartTime(varchar) SlotEndTime(varchar)
1 8:00AM 8:15AM
2 8:15AM 8:30AM
3 8:30AM 8:45AM
and goes on till 7:00PM
I have another table DrDutyDetails in which DrTiming is set for whole month like this.
DrID StartTime EndTime DateOfAllocation
1 4/5/2009 8:00:00 AM 4/5/2009 9:30:00 AM 4/5/2009 12:00:00 AM
2 4/12/2009 8:00:00 AM 4/12/2009 9:30:00 AM 4/12/2009 12:00:00 AM
likewise
I have another table called AppointmentSchedule which gets filled when patient requests appointment
AppointmentID SlotID AppointmentDate
1 1 4/5/2009
2 3 4/12/2009
i have a appointment schedule form in which i selects DrID and Appointment date.Then slots corresponding to date that has not been in Appointmentschedule,but slots should be in between starttime and endtime that in DrTimings and in TimeSlots should get filled in a dropdownlist.I need a query to implement this.
for eg:If Patient enters '4/5/2009' Then slots other than 1 and 3 but biw DrTimings i want to get.
Similarly i want to search by time.Means if Patient enters any time b/w DrTimings for eg:8:30AM,Then available first date has to be displayed in textbox

You are going to need to look at doing some Casting/COnverting of date values. This MSDN article gives you a bit of information on what you need to work with.
There are a number of ways that you can do this, but ideally you can do something like CONVERT(VARCHAR(50), StartTime) to get the fully formatted time. Then, since you know that the ending format of that is 08:00AM, you can do a RIGHT(CONVERT(VARCHAR(50), StartTime), 7), which will get you just the time value.
Now, with that you know how to manipulate the date into parts, you can from here, do the various things needed to query your items.
For comparison sake, I would be storing the "TimeList" data as DateTime values, that way you can use standard time comparisons to actually allow you to use functions such as "Between" and similar. You could store them as 1/1/1900 08:00AM or similar. But this would require a data model change. If you want some helpful SQL for this type of thing, here is a great article on "Essential SQL Server Date, Time, and DateTime Functions".

Related

Cumulative count in SQL

I am working on SQL and came across one scenario that needs to build in SQL.
Below is scenario:
PatientID AdmitDate DischargeDate
12 7/24/2017 09:45 7/24/2017 11:01
13 7/21/2016 08:37 7/22/2017 00:15
I want result set as below:
For patientID 13, count is calculated in first 2 rows and
For patientid 12, count is calculated in last row.
Well, that looks like whatever you do will be slow. I think I'd use a tally table. The table, instead of just containing the usual n years worth of dates / days / day of week etc. would also contain one record for each hour in the day. The Primary Key would represent one of those segments.
Then you could pass the admission date and discharge date for a patient to a function that would return a list, or range, of the hours that the patient is in for. So, Patient 13 might get a return value of (for example) 1500,1517 (i.e the patient was in for 17 hours and you will know the date and time because 1500 will be the Primary Key of a record that gives you the date and hour of the day he was admitted). Patient 12 would (to continue the example) return a value of 1544,1546
You could then build the dataset from Date A to Date B by returning all the data between those dates from the tally table and then check whether each hour is a yes or no for a particular patient.
The display of the data - your desired result set - I would do in somewhere else. I'd probably return two datasets. One would be used to build your table structure. The other would be used to decide whether to put a '1' in the box or not. You could do your summing on the fly.
I imagine this would get interesting with patients on the same dates ... you'd have to show each patient separately?

Excel: Insert blank row if non consecutive date

We have a process at work that runs every 31 hours and would like to have a column in an Excel 2010 spreadsheet that reflects the time and dates the process is due to run each day over the coming year e.g.
start date (Cell:A1):
10/31/2016 1:00
11/1/2016 8:00
11/2/2016 15:00
11/3/2016 22:00
11/5/2016 5:00
11/6/2016 12:00
11/7/2016 19:00
11/9/2016 2:00
11/10/2016 9:00
11/11/2016 16:00
11/12/2016 23:00
11/14/2016 6:00
I am currently using the formula: A2 =A1 + (31/24) to populate the dates and times in the column which appears to work ok. I need to insert a blank row between days that are not consecutive (in order to highlight that fact, to make it easier for the operators to read and not instigate the process at the wrong time!) which is where the difficulty lies. I am assuming that I will need a separate VBA function to step through each cell and compare the day date (ignoring time value.) in the previous cell, if day date is greater than 1 (as in not the following day.) insert a blank row.
I am looking for a solution to the following scenario but am struggling to get my head round it and would appreciate any guidance/ help anyone is able to provide.
Many thanks
You do not need a VBA Function for that, it can be accomplished with the function
A3 = IF(A2="",A1+31/24, IF(INT(A2+31/24)=INT(A2)+1,A2+31/24,""))
*For that to work, you will have to populate cells A1 and A2 manually, though.
You can use the INT() function to get the date part of a DateTime field, so it becomes simple to check if adding 31 hours will leave a 1 day gap in the sequence by checking INT(A2+31/24) = INT(A2)+1.
So, to explain the function, the part
IF(INT(A2+31/24)=INT(A2)+1,A2+31/24,"")
will check if the days are consecutive, and if so, it will fill the DateTime. If not, it will leave it blank.
The outer IF checks if the cell above is blank. If it is, the function will use the one above that.

how to insert data into table based on dates and frequency in MS Access 2007

I'm new to MS Access and my question has two parts, I'm working on Database to schedule jobs based on [StartDate], [EndDate] and [Frequency(Days)] of task, for example if the startdate is 01/01/2015 and the enddate is 31/12/2015 and Frequency is 30 days, then the query should add 12 dates like 31/01/2015, 01/03/2015, 31/03/2015....26/12/2015.
The second part of my question, if after two months I have changed the date like instead of 31/03/2015 the date has been changed manually to 05/04/2015 then the data should automatically changed from 05/04/2015 until 31/12/2015 without changing the completed dates from 01/01/2015 to 05/04/2015.

Storing a time difference in SQL

In my application, I have a database storing a calendar of events:
id | name | date
----+--------------------+--------------------
1 | Birthday Party | 2013-04-27 16:30:00
2 | Dinner Reservation | 2013-03-20 17:00:00
3 | Sunday Brunch | 2013-03-31 11:15:00
When viewing events in the application, users should be able to configure how far in advance from the present moment they wish to view events, stored as a value in the database:
username | datediff
----------+------------------------------------------
user123 | 2 days in advance
goodguy | 93 days in advance
spudly | 365 days in advance
aaaaaa | 17 days, 3 hours, 30 seconds in advance
My question is: what is the best (i.e., most SQL-idiomatic) way to store such a date differential? I could store the time difference as a number in milliseconds, but is there some built-in SQL datatype that is suitable for date differentials, rather than just particular points in time? Is something like DATETIME or TIMESTAMP appropriate for this task?
It must be a relative difference -- for example, for "2 days in advance" I'm not interested in storing a particular date two days in the future, because I'd like the user to see events for the next two days every time he looks at the application.
I'm using Microsoft SQL Server 2008, if it makes any difference.
(This may be a duplicate, but all my search attempts have turned up results about datediff -- which is used to calculate time differences -- but nothing about how best to store time differences.)
Standard SQL has a specific data type for date and time durations: interval. SQL Server doesn't support the interval data type.
DateDiff() returns a signed integer. If you need to store the SQL Server equivalent to a SQL interval, you'll need to store an integer. The integer is a count of the number of datepart boundaries, so you also need to store what kind of datepart boundary the integer refers to. Without the datepart, the signed integer 3 could just as easily mean 3 years or 3 seconds.
As a practical matter, I think I'd rather calculate a timestamp for the reminder, and store that instead of the integer and datepart that define an interval. A timestamp can be indexed and queried much more simply than the integer and datepart. And without the need to support recurring events, I don't see a compelling reason to build a solution more complicated than that.

How do I compare overlapping values within a row?

I seem to have a problem with this SQL query:
SELECT * FROM appts
WHERE timeStart >='$timeStart'
AND timeEnd <='$timeEnd'
AND dayappt='$boatdate'
The time is formatted as military time. The logistics is that a boat rental can be reserved at 7am til 1pm or 9am til 1pm or 9am til 5pm. If there is an appt within that range, it should return appts but it has proven to be inconsistent. If I pick 9am til 1pm, it will ignore appts that started with 7am even though it overlaps 9am-1pm. If I pick 9 to 5, it will return nothing even though it should with the 7am to 1pm. How do I make a SQL statement that includes the whole range from timeStart to timeEnd including those that overlap?
Shahkalpesh answered the question with:
I think you need an OR.
SELECT * FROM appts
WHERE (timeStart >='$timeStart'
OR timeEnd <='$timeEnd')
AND dayappt='$boatdate'
I posted a comment that I consider this to be wrong, giving a pair of counter-examples:
This is plain wrong - #ShaneD is correct. For example, this will pick out a booking between 05:00 and 06:00 because the actual end time is less than any of the end times you ask about. It will also pick up rentals from 18:00 onwards, for the equivalent reason.
In a response to my comment, Shahkalpesh requested:
Could you post a separate reply with data & input parameters with expected output?
Fair enough - yes. Slightly edited, the question says:
The logic is that a boat rental can be reserved
from 7am until 1pm, or
from 9am until 1pm, or
from 9am until 5pm.
If there is an appointment within that range, it should return appointments but it has proven to be inconsistent. If I pick 9am until 1pm, ...
Enough background. We can ignore the date of the appointments, and just consider the times. I'm assuming that there is an easy way to limit the times recorded to hh:mm format; not all DBMS actually provide that, but the extension to handle hh:mm:ss is trivial.
Appointments
Row timeStart timeEnd Note
1 07:00 13:00 First valid range
2 09:00 13:00 Second valid range
3 09:00 17:00 Third valid range
4 14:00 17:00 First plausibly valid range
5 05:00 06:00 First probably invalid range
6 18:00 22:30 Second probably invalid range
Given a search for appointments overlapping the range 09:00 - 13:00, Shahkalpesh's (simplified) query becomes:
SELECT * FROM Appointments
WHERE (timeStart >= '09:00' OR timeEnd <= '13:00')
This will return all six rows of data. However, only rows 1, 2, 3 overlap the time period 09:00 - 13:00. If rows 1, 2, and 3 are the only valid representative appointment values, then Shahkalpesh's query produces the correct answer. However, if the row 4 (which I think is plausibly valid) is permitted, then it should not be returned. Similarly, rows 5 and 6 - if present - should not be returned. [Actually, assuming timeStart <= timeEnd for all rows in the table (and there are no NULL values to mess things up), we can see that Shahkalpesh's query will return ANY row of data for the 09:00-13:00 query because either the start time of the row is greater 09:00 or the end time is less than 13:00 or both. This is tantamount to writing 1 = 1 or any other tautology in the WHERE clause.]
If we consider ShaneD's query (as simplified):
SELECT * FROM Appointments
WHERE timeStart <= '13:00' AND timeEnd >= '09:00'
we see that it also selects rows 1, 2, and 3, but it rejects rows 4 (because timeStart > '13:00'), 5 (because timeEnd < '09:00') and 6 (because timeStart > '13:00'). This expression is an archetypal example of how to select rows which 'overlap', counting 'meets' and 'met by' (see "Allen's Interval Algebra", for instance) as overlapping. Changing '>=' and '<=' alters the set of intervals counted as overlapping.
The correct check would look like this:
SELECT * FROM appts
WHERE timeStart <='$timeEnd'
AND timeEnd >='$timeStart'
AND dayappt='$boatdate'
Other good explanations have been given but I'll go ahead and update it with an alternative explanation of how I visualize this myself. Most people are looking for each possible overlap, considering two time periods, they are trying to think of each combination of start and end that can make an appointment overlap. I think about it as when do two time periods not overlap which for some reason is easier for me.
Say the time period I am checking for is today, I want to find any time period that does not overlap today. There are really only two scenarios for that, either the time period starts after today (PeriodStart > EndOfToday) or the time period ends before today (PeriodEnd < StartOfToday).
Given that we havea simple test for not overlapping:
(PeriodStart > EndOfToday) OR (PeriodEnd < StartOfToday)
A quick flip around and you have a simple test for overlap:
(PeriodStart <= EndOfToday) AND (PeriodEnd >= StartOfToday)
-Shane
Thanks Shane, Shahkalpesh, and Jonathan.
I actually overlooked the fact that Shane "swapped" the variables (I was still using timeStart<=$timeStart when it should be timeStart <= $timeEnd). I ran with the modified statement as Jonathan/Shane suggested and it works. As Jonathan did point out, I did obviously missed out some time ranges that I should have tested against.
Now with Jonathan's explanation, I now get a better picture of my mistake is and it's helpful.
I think you need an OR.
SELECT * FROM appts
WHERE (timeStart >='$timeStart'
OR timeEnd &LT;='$timeEnd')
AND dayappt='$boatdate'
Assuming each record cares about only a specific day.
i.e. Boats rented don't run across more than 1 day.