Always Include Certain Records in Daterange - sql

Sorry if this is too general a question, but I couldn't find much material on this.
I'm wondering if there is any way in SQL or Tableau to always include certain records despite changes in a date range?
For example, I have 200 records that range from 1940-2004 and want 2 or 3 of these records to always be returned in the query (which includes a date range statement) is there a known method?
I'd like to avoid altering the date attributes based on the date range statement itself is possible.
Initial data:
Person_ID | Group | Date
ID 1 2 1-1-2003
ID 2 1 1-1-1994
ID 3 1 1-1-1985
ID 4 1 1-1-1992
ID 5 2 1-1-1991
ID 6 2 1-1-2002
ID 7 1 1-1-2003
ID 8 2 1-1-2005
ID 9 2 1-1-1999
ID 10 1-1-2002
ID 11 1-1-1989
For my results, I want it to be possible so that no matter the daterange I select, ID 10 and ID 11 are included.
SELECT Person_ID
FROM table
WHERE DATE BETWEEN date1 AND date2
Will always yield ID 10 and ID 11 no matter the dates inputted.

I don't know much about tableau but you can try this...
SELECT Person_ID
FROM table
WHERE (DATE BETWEEN date1 AND date2) OR Person_ID = 10 OR Person_ID = 11
If you want help on figuring out queries try and say what you want as literal as possible using sql words. So in this case you could say "I want to select the person_id from table where the date is between date1 and date2 or if the person_id is 10 or if the person_id is 11". If you ever say but (ex: date between date1 and date2 but if their id is 10 then also do it) then most likely you can put an or there : ). So if I were to do it without the or it sound more normal (in my opinion at least -> "where the date is between date1 and date2 but if the person_id is 10 or 11 also include it"). Hope that helps!

Related

PostgreSQL - Generate series using subqueries

Using PostgreSQL, I need to accomplish the following scenario. I have a table called routine, where I store start_date and end_date columns. I have another table called exercises, where I store all the data related with each exercise and finally, I have a table called routine_exercise where I create the relationship between the routine and the exercise. Each routine can have seven days (one day indicates the day of the week, e.g: 1 means Monday, etc) of exercises and each day can have one or more exercise. For example:
Exercise Table
Exercise ID
Name
1
Exercise 1
2
Exercise 2
3
Exercise 3
Routine Table
Routine ID
Name
1
Routine 1
2
Routine 2
3
Routine 3
Routine_Exercise Table
Exercise ID
Routine ID
Day
1
1
1
2
1
1
3
1
1
1
1
2
2
1
3
3
1
4
The thing that I'm trying to do is generate a series from start_date to end_date (e.g 03-25-2020 to 05-25-2020, two months) and assign to each date the number of day it supposed to work.
For example, using the data in the Routine_Exercise Table the user should only workout days: 1,2,3,4, so I would like to attach that number to each date. For example, something like this:
Expected Result
Date
Number
03-25-2020
1
03-26-2020
2
03-27-2020
3
03-28-2020
4
03-29-2020
null
03-30-2020
null
03-31-2020
null
04-01-2020
1
04-02-2020
2
04-03-2020
3
04-04-2020
4
04-05-2020
null
Any suggestions or different ideas on how to implement this? Another solution that doesn't require series?
Thanks in advance!
You can generate the dates between start and end input dates using generate_series and then do left join with your routine_exercise table as follows:
SELECT t.d, re.day
FROM generate_series(timestamp '2020-03-25', timestamp '2020-05-25',
interval '1 day') AS t(d)
left join (select distinct day from Routine_Exercise re WHERE ROUTINE_ID = 1) re
on mod(extract(day from (t.d -timestamp '2020-03-25')), 7) + 1 = re.day;

SQL Query to Count IDs

I'm trying to write a SQL Query in MS Access to count the number of times each ID appears in a data set. The data set is formatted as follows:
ID Time
1 12345
1 12346
1 12350
2 99999
2 99999
If the Time for one ID is within 3 seconds of another Time for that same ID, I only want it to be counted once. So the results should look like this:
ID Count
1 2
2 1
The time column is not formatted as a datetime, so I can't use the datediff function. Any help would be appreciated.
This:
SELECT ID, COUNT(newtime)
FROM (SELECT DISTINCT ID, Time\3 AS newtime FROM times)
GROUP BY ID
groups the Time field values in triples using the integer division for Time\3 in Access.
The comment provided by #Andy G worked for my purposes:
"You first need a function to round up (or down) to the nearest multiple of 3. See here (allenbrowne) for example."
I rounded the time values to the nearest multiple of 3, and counted based on that criteria.

SQL Find latest record only if COMPLETE field is 0

I have a table with multiple records submitted by a user. In each record is a field called COMPLETE to indicate if a record is fully completed or not.
I need a way to get the latest records of the user where COMPLETE is 0, LOCATION, DATE are the same and no additional record exist where COMPLETE is 1. In each record there are additional fields such as Type, AMOUNT, Total, etc. These can be different, even though the USER, LOCATION, and DATE are the same.
There is a SUB_DATE field and ID field that denote the day the submission was made and auto incremented ID number. Here is the table:
ID NAME LOCATION DATE COMPLETE SUB_DATE TYPE1 AMOUNT1 TYPE2 AMOUNT2 TOTAL
1 user1 loc1 2017-09-15 1 2017-09-10 Food 12.25 Hotel 65.54 77.79
2 user1 loc1 2017-09-15 0 2017-09-11 Food 12.25 NULL 0 12.25
3 user1 loc2 2017-08-13 0 2017-09-05 Flight 140 Food 5 145.00
4 user1 loc2 2017-08-13 0 2017-09-10 Flight 140 NULL 0 140
5 user1 loc3 2017-07-14 0 2017-07-15 Taxi 25 NULL 0 25
6 user1 loc3 2017-08-25 1 2017-08-26 Food 45 NULL 0 45
The results I would like is to retrieve are ID 4, because the SUB_DATE is later that ID 3. Which it has the same Name, Location, and Date information and there is no COMPLETE with a 1 value.
I would also like to retrieve ID 5, since it is the latest record for the User, Location, Date, and Complete is 0.
I would also appreciate it if you could explain your answer to help me understand what is happening in the solution.
Not sure if I fully understood but try this
SELECT *
FROM (
SELECT *,
MAX(CONVERT(INT,COMPLETE)) OVER (PARTITION BY NAME,LOCATION,DATE) AS CompleteForNameLocationAndDate,
MAX(SUB_DATE) OVER (PARTITION BY NAME, LOCATION, DATE) AS LastSubDate
FROM your_table t
) a
WHERE CompleteForNameLocationAndDate = 0 AND
SUB_DATE = LastSubDate
So what we have done here:
First, if you run just the inner query in Management Studio, you will see what that does:
The first max function will partition the data in the table by each unique Name,Location,Date set.
In the case of your data, ID 1 & 2 are the first partition, 3&4 are the second partition, 5 is the 3rd partition and 6 is the 4th partition.
So for each of these partitions it will get the max value in the complete column. Therefore any partition with a 1 as it's max value has been completed.
Note also, the convert function. This is because COMPLETE is of datatype BIT (1 or 0) and the max function does not work with that datatype. We therefore convert to INT. If your COMPLETE column is type INT, you can take the convert out.
The second max function partitions by unique Name, Location and Date again but we are getting the max_sub date this time which give us the date of the latest record for the Name,Location,Date
So we take that query and add it to a derived table which for simplicity we call a. We need to do this because SQL Server doesn't allowed windowed functions in the WHERE clause of queries. A windowed function is one that makes use of the OVER keyword as we have done. In an ideal world, SQL would let us do
SELECT *,
MAX(CONVERT(INT,COMPLETE)) OVER (PARTITION BY NAME,LOCATION,DATE) AS CompleteForNameLocationAndDate,
MAX(SUB_DATE) OVER (PARTITION BY NAME, LOCATION, DATE) AS LastSubDate
FROM your)table t
WHERE MAX(CONVERT(INT,COMPLETE)) OVER (PARTITION BY NAME,LOCATION,DATE) = 0 AND
SUB_DATE = MAX(SUB_DATE) OVER (PARTITION BY NAME, LOCATION, DATE)
But it doesn't allow it so we have to use the derived table.
So then we basically SELECT everything from our derived table Where
CompleteForNameLocationAndDate = 0
Which are Name,Location, Date partitions which do not have a record marked as complete.
Then we filter further asking for only the latest record for each partition
SUB_DATE = LastSubDate
Hope that makes sense, not sure what level of detail you need?
As a side, I would look at restructuring your tables (unless of course you have simplified to better explain this problem) as follows:
(Assuming the table in your examples is called Booking)
tblBooking
BookingID
PersonID
LocationID
Date
Complete
SubDate
tblPerson
PersonID
PersonName
tblLocation
LocationID
LocationName
tblType
TypeID
TypeName
tblBookingType
BookingTypeID
BookingID
TypeID
Amount
This way if you ever want to add Type3 or Type4 to your booking information, you don't need to alter your table layout

rows to columns in sql (not all the rows)

i am trying convert the row data into column in SQL, here is the data i have in my table
ID NAME DATE STATUS
1 A 1/1/15 START
1 A 1/20/15 END
I want result as
ID NAME START_DATE END_DATE
1 A 1/1/15 1/20/15
Any help will be appreciated
Check out Pivot.. Seems to be what you are looking to do.
https://technet.microsoft.com/en-us/library/ms177410(v=sql.105).aspx

Oracle Database Temporal Query Implementation - Collapse Date Ranges

This is the result of one of my queries:
SURGERY_D
---------
01-APR-05
02-APR-05
03-APR-05
04-APR-05
05-APR-05
06-APR-05
07-APR-05
11-APR-05
12-APR-05
13-APR-05
14-APR-05
15-APR-05
16-APR-05
19-APR-05
20-APR-05
21-APR-05
22-APR-05
23-APR-05
24-APR-05
26-APR-05
27-APR-05
28-APR-05
29-APR-05
30-APR-05
I want to collapse the date ranges which are continuous, into intervals. For examples,
[01-APR-05, 07-APR-05], [11-APR-05, 16-APR-05] and so on.
In terms of temporal databases, I want to 'collapse' the dates. Any idea how to do that on Oracle? I am using version 11. I searched for it and read a book but couldn't find/understand how to do it. It might be simple, but everyone has their own flaws and Oracle is mine. Also, I am new to SO so my apologies if I have violated any rules. Thank You!
You can take advantage of the ROW_NUMBER analytical function to generate a unique, sequential number for each of the records (we'll assign that number to the dates in ascending order).
Then, you group the dates by difference between the date and the generated number - the consecutive dates will have the same difference:
Date Number Difference
01-APR-05 1 1 -- MIN(date_val) in group with diff. = 1
02-APR-05 2 1
03-APR-05 3 1
04-APR-05 4 1
05-APR-05 5 1
06-APR-05 6 1
07-APR-05 7 1 -- MAX(date_val) in group with diff. = 1
11-APR-05 8 3 -- MIN(date_val) in group with diff. = 3
12-APR-05 9 3
13-APR-05 10 3
14-APR-05 11 3
15-APR-05 12 3
16-APR-05 13 3 -- MAX(date_val) in group with diff. = 3
Finally, you select the minimal and maximal date in each of the groups to get the beginning and ending of each range.
Here's the query:
SELECT
MIN(date_val) start_date,
MAX(date_val) end_date
FROM (
SELECT
date_val,
row_number() OVER (ORDER BY date_val) AS rn
FROM date_tab
)
GROUP BY date_val - rn
ORDER BY 1
;
Output:
START_DATE END_DATE
------------ ----------
01-04-2005 07-04-2005
11-04-2005 16-04-2005
19-04-2005 24-04-2005
26-04-2005 30-04-2005
You can check how that works on SQLFidlle: Dates ranges example