SQL Query to check ALL days exist between a date range - sql

I have a table of Prices with a start date, end date and price. I want a search to pass in a date range and return whether a price exists for all days in that range. The date range can span multiple prices, just not have any gaps in between.
Is this possible?
Prices
startDate datetime
endDate datetime
price
DECLARE #startDate datetime = '2010-04-01',
#endDate datetime = '2010-04-30'
SELECT * FROM Prices WHERE #startDate BETWEEN startDate AND endDate...

Add a grouping to your query with a having statement :
HAVING COUNT(*) = DATEDIFF(DAY,#StartDate,#EndDae)+1

Related

Generate List of dates between 2 dates for each Id

I have a table with PersonId's that each have a FirstSubscription date and LastSubscriptionDate.
What I need to do is between those 2 dates, generate 1 date for each month. This is for reporting purposes on the front end, as this data will end up inside PowerBI and I need these dates to join to a ReportingCalendar.
This Calendar is accessible by SQL so it can be used in this calculation. I am using it to generate the dates (using first of the month) between the First and LastSubDate but I need to find a way to join this with the rest of the ID's that way I get a list of date for each ID.
Here is my code to generate the dates.
DECLARE #MinDate DATE
DECLARE #MaxDate DATE
SET #MinDate = '2020-08-31'
SET #MaxDate = '2022-08-30'
SELECT DATEADD(month, DATEDIFF(month, 0, date), 0)
FROM dbo.ReportingCalendar
WHERE Date >= #MinDate
AND Date < #MaxDate
GROUP BY
DATEADD(month, DATEDIFF(month, 0, date), 0)
My PersonSubscription table looks like this
|PersonId|FirstSubDate|LastSubDate|
|--------|------------|-----------|
|1186 |8/31/2020 |8/30/2022 |
|2189 |7/30/2019 |7/31/2021 |
So I would want to end up with an output where each PersonId has 1 entry for each month between those 2 dates. So PersonId has 25 entries from 8/2020 until 8/2022. We don't care about the actual date of the sub since this data is looked at monthly and will primarily be looked at using a Distinct Count each month, so we only care if they were subbed at any time in that month.
I just needed to do a Cross Apply.
I took my code that got me all of the PersonId's and their FirstSubDate and LastSubDate and then did a cross apply to the code I listed above, referencing the MinDate and MaxDate with the FirstSubDate and LastSubDate.

Calculating daily average transaction balance of IDs

need to calculate daily average balance of ids. firstdate is when the ID was generated, currentdate is the dates with balance shown for the IDs.
I am expecting something like this [image 2](manually calculated) for each IDs. So basically need to calculate numbers of days between the firstdate when the id was generated and the last currentdate and the balance should be filled in the blank (between dates) to accurately calculating the daily average.
I created the calender table but not sure how I can get the balance for everyday in order to calculate the average.
CREATE TABLE #Calendar
(
[CalendarDate] DATE
)
DECLARE #StartDate DATE
DECLARE #EndDate DATE
SET #StartDate = '20000101'
SET #EndDate = GETDATE()
WHILE #StartDate <= #EndDate
BEGIN
INSERT INTO #Calendar
(
CalendarDate
)
SELECT
#StartDate
SET #StartDate = DATEADD(day, 1, #StartDate)
Thanks for any help.
Assuming the last observation is weighted to getdate()
There is no need for a calendar table, you can use the window function lead() over() to determine the number of days.
Example
Select ID
,ADB = sum(Balance*Days)/sum(Days)
From (
Select *
,Days = datediff(Day,CurrentDate,lead(CurrentDate,1,getdate() ) over (partition by ID order by CurrentDate ) )
from YourTable
) A
Group By ID
Results
ID ADB
110 109.5597
EDIT
I should add that the window functions can invaluable. They are well worth your time getting comfortable with them.

SQL get customers by age

How i can get a list of customers, whose age will be 5 or 10 years on a given interval of two dates ?
The query for only one date is:
SELECT * FROM Customers C
WHERE DATEDIFF(MONTH,C.StartDate,#Date)=60
OR DATEDIFF(MONTH, C.StartDate,#Date)=120
You want customers where they are 5 or less at the start and 5 or greater at the end - this means that at some point in the range they were 5.
SELECT * FROM Customers C
WHERE (DATEDIFF(MONTH,C.StartDate,#StartDate)<=60 AND DATEDIFF(MONTH,C.StartDate,#EndDate) >=60)
OR (DATEDIFF(MONTH,C.StartDate,#StartDate)<=120 AND DATEDIFF(MONTH,C.StartDate,#EndDate) >=120)
You can use a query like below
See live demo
DECLARE #Date1 DATE
DECLARE #Date2 DATE
SET #Date1='03-19-2017'
SET #Date2='12-19-2017'
SELECT * FROM Customers C
WHERE ( DATEADD(m, 60,C.StartDate) BETWEEN #Date1 AND #Date2 )
OR
(DATEADD(m, 120,C.StartDate) BETWEEN #Date1 AND #Date2)
The syntax of T-SQL's datediff function is:
DATEDIFF ( datepart , startdate , enddate )
The order of dates IS important, to get a positive integer result the earlier date should be first and the later date should be second. If you do it the other way the results will be negative numbers.
You can overcome this by using ABS()
ABS( DATEDIFF ( datepart , date1 , date2 ) )

Calculating last 7 days for each day in range

My table (products) is as follow:
id, productId, price, saleDate
I want to build a query that for specific productId and specific data range will return the average of the price for the last 7 days for each day in the range.
The following query will give me all the data for specific productId between 1/1/16 and 02/01/16
SELECT * FROM products WHERE productId='PS54434' AND saleDate BETWEEN '2016-01-01' AND '2016-02-01'
BUT I want that for each day 01/01/16 until 02/01/16 I will receive the last 7 days
so for data 01/01/16 I will receive the average of prices from the 12/26/16-01/01/16
One way to do it is using a loop. You declare a start date and go back 7 days from that date and get the average price for that date range. Then add 1 day and repeat the process. If you need all the results as a table, create a temp table and store the result from each iteration.
declare #startdate date = '2016-01-01';
create table #tmpavgprice (price numeric(10,2));
while #startdate <= '2016-02-01'
begin
SELECT avg(price)
INTO #tmpavgprice
FROM products
WHERE productId='PS54434'
AND saleDate BETWEEN dateadd(dd,-7,#startdate) AND #startdate;
set #startdate = select dateadd(dd,1,#startdate);
end;
select * from #tmpavgprice; --to get the final result

Checking for date range conflicts with Access

I'm having trouble writing a query that will tell me if a given car is booked for a specified date period. My table is called Bookings and has CarID, StartDate and EndDate columns. I want to return a row if the car is booked for the period that the user enters. At the moment I have this query, which I got from the internet and some tinkering:
SELECT *
FROM Bookings
WHERE BookingID NOT IN
(SELECT BookingID
FROM Bookings
WHERE
(StartDate <= user_start_date AND EndDate >= user_start_date) OR
(StartDate <= user_end_date AND EndDate >= user_end_date) OR
(StartDate >= user_start_date AND EndDate <= user_end_date)) AND
(CarID = 7)
Here, I'm using user_start_date as my start date from the user and user_end_date as the end date from the user, and 7 for the car. However, the logic doesn't seem to work. Even when I verify there's absolutely no clashes in the dates it always returns rows.
How can I ammend this query so it works?
Thanks
Assuming that none of the dates can be null, and the start dates are less than the end dates, the following query should list any bookings for car 7 that overlap the given date range:
SELECT *
FROM Bookings
WHERE CarID = 7
AND StartDate < user_end_date
AND EndDate > user_start_date