MS SQL Server GETDATE - 90 where -90 not like previous - sql

Today for me is 2017-08-02 13:00:00.000 and I have this table :
TABLE1
TIME NAME PRODUCT
2014-10-10 08:34:57.000 Bob Glu
2015-11-03 13:34:27.000 Bob Finger
2017-07-08 09:51:46.000 Bob Note
2017-07-08 09:51:46.000 Bob PC
2017-07-31 09:51:46.000 Bob Car
2017-07-31 09:51:46.000 Bob Ball
2017-07-31 09:51:46.000 Bob Shoe
2017-04-01 08:34:57.000 Alex Pen
2017-06-03 13:34:27.000 Alex Horse
2017-07-31 05:51:46.000 Alex Bread
2017-07-31 09:51:46.000 Alex Hummus
2017-07-31 09:51:46.000 Alex Kitchen
2017-07-31 09:51:46.000 Alex Hell
2017-07-31 09:51:46.000 Alex Night
2016-10-10 08:34:57.000 Eva Mouse
2017-05-03 13:34:27.000 Eva Cement
2017-06-31 06:51:46.000 Eva Pc
2017-06-31 03:51:46.000 Eva Bread
2017-06-31 08:51:46.000 Eva Shoe
2017-06-31 07:51:46.000 Eva Ball
2017-06-31 07:51:46.000 Eva Zoo
I need to know which PRODUCT was lost from the above table, but I need to know only PRODUCT which was lost from last (TIME + NAME) and – 90 days. I expect results like this:
TABLE1
TIME NAME Product
2017-05-03 13:34:27.000 Eva Cement
2017-06-03 13:34:27.000 Alex Horse
2017-07-08 09:51:46.000 Bob Note
2017-07-08 09:51:46.000 Bob PC
The table has millions of names and millions of products. At the moment I am interest for 90 days from the last updates.
I am trying
SELECT * from table1
WHERE (TIME > getdate ()- 90) AND (TIME not like getdate ()- 90)

Try where DATEDIFF(day, TIME, GETDATE()) < 90

are you trying to figure out the first thing each person lost in the past 90 days? and include all ties?
Lets limit data and add a window function in a cte and then limit the data to just #1's
;with cte as
(
SELECT * , DENSE_RANK() over (partition by [name] order by [time]) as DR
from table1
WHERE [time] >= dateadd('d',-90,getdate())
)
select *
from cte
where dr=1

If you want rows from the previous 90 days from today.
select * from table1
where TIME >= getdate()-90

Related

JOIN Tables based on Service Date

I have 2 Tables (History and Responsible). They need to be JOINED based on Service Date.
History Table:
Id
ServiceDate
Hours
ClientId
ClientName
1
2021-10-15
3
123
Tom Holland
2
2021-10-25
5
123
Tom Holland
3
2022-01-14
2
123
Tom Holland
Responsible Table:
2999-12-31 means Responsible has no end date (current)
ClientId
ClientName
ResponsibleId
ResponsibleName
ResponsibleStartDate
ResponsibleEndtDate
123
Tom Holland
77
Thomas Anderson
2020-09-17
2021-10-17
123
Tom Holland
88
Tom Cruise
2021-10-18
2999-12-31
123
Tom Holland
99
Sten Lee
2022-01-07
2999-12-31
My code produces multiple rows, because 2022-01-14 Service date falls under multiple date ranges from Responsible Table:
SELECT h.Id,
h.ServiceDate,
h.Hours,
h.ClientId,
h.ClientName,
r.ResponsibleName
FROM History AS h
LEFT JOIN Responsible AS r
ON (h.ClientId = r.ClientId AND h.ServiceDate BETWEEN r.ResponsibleStartDate AND r.ResponsibleEndtDate)
The output of the query above is:
Id
ServiceDate
Hours
ClientId
ClientName
ResponsibleName
1
2021-10-15
3
123
Tom Holland
Thomas Anderson
2
2021-10-25
5
123
Tom Holland
Tom Cruise
3
2022-01-14
2
123
Tom Holland
Tom Cruise
3
2022-01-14
2
123
Tom Holland
Sten Lee
Technically, output is correct (because 2022-01-14 is between 2021-10-18 - 2999-12-31 as well between 2022-01-07 - 2999-12-31), but not what I need.
I would like to know if possible to achieve 2 outputs:
1) If Service Date falls in multiple date ranges from Responsible Table, Responsible Should be the person who's ResponsibleStartDate is closer to the ServiceDate:
Id
ServiceDate
Hours
ClientId
ClientName
ResponsibleName
1
2021-10-15
3
123
Tom Holland
Thomas Anderson
2
2021-10-25
5
123
Tom Holland
Tom Cruise
3
2022-01-14
2
123
Tom Holland
Sten Lee
2) Keep all rows, if Service Date falls in multiple date ranges from Responsible Table, but split Hours evenly between Responsible:
Id
ServiceDate
Hours
ClientId
ClientName
ResponsibleName
1
2021-10-15
3
123
Tom Holland
Thomas Anderson
2
2021-10-25
5
123
Tom Holland
Tom Cruise
3
2022-01-14
1
123
Tom Holland
Tom Cruise
3
2022-01-14
1
123
Tom Holland
Sten Lee
First one, we can use a window function to apply a row number, based on how close to ServiceDate the ResponsibleStartDate is, then we can just pick the first row per h.Id. If there is a tie we can break it by picking something that will give us deterministic order, e.g. ORDER BY {DATEDIFF expression}, ResponsibleName.
;WITH cte AS
(
SELECT h.Id,
h.ServiceDate,
h.Hours,
h.ClientId,
h.ClientName,
r.ResponsibleName,
RankOrderedByProximityToServiceDate = ROW_NUMBER() OVER
(PARTITION BY h.Id
ORDER BY ABS(DATEDIFF(DAY, ResponsibleStartDate, ServiceDate)))
FROM dbo.History AS h
LEFT JOIN dbo.Responsible AS r
ON (h.ClientId = r.ClientId
AND h.ServiceDate BETWEEN r.ResponsibleStartDate AND r.ResponsibleEndtDate)
)
SELECT Id, ServiceDate, Hours, ClientId, ClientName, ResponsibleName
FROM cte WHERE RankOrderedByProximityToServiceDate = 1;
Output:
Id
ServiceDate
Hours
ClientId
ClientName
ResponsibleName
1
2021-10-15
3
123
Tom Holland
Thomas Anderson
2
2021-10-25
5
123
Tom Holland
Tom Cruise
3
2022-01-14
2
123
Tom Holland
Sten Lee
Second one doesn't require a CTE, we can simply divide the Hours in h by the number of rows that exist for that h.Id, then limit it to 2 decimal places:
SELECT h.Id,
h.ServiceDate,
Hours = CONVERT(decimal(11,2),
h.Hours * 1.0
/ COUNT(h.Id) OVER (PARTITION BY h.Id)),
h.ClientId,
h.ClientName,
r.ResponsibleName
FROM dbo.History AS h
LEFT JOIN dbo.Responsible AS r
ON (h.ClientId = r.ClientId
AND h.ServiceDate BETWEEN r.ResponsibleStartDate AND r.ResponsibleEndtDate);
Output:
Id
ServiceDate
Hours
ClientId
ClientName
ResponsibleName
1
2021-10-15
3.00
123
Tom Holland
Thomas Anderson
2
2021-10-25
5.00
123
Tom Holland
Tom Cruise
3
2022-01-14
1.00
123
Tom Holland
Tom Cruise
3
2022-01-14
1.00
123
Tom Holland
Sten Lee
Both demonstrated in this db<>fiddle.
My attempt at part 1 - it doesn't work if there's more than one Responsible as of the same start date.
WITH
"all_services" AS (
SELECT
h.Id,
h.ServiceDate,
h.Hours,
h.ClientId,
h.ClientName,
r.ResponsibleName,
r.ResponsibleStartDate
FROM History AS h
LEFT JOIN Responsible AS r
ON h.ClientId = r.ClientId
AND h.ServiceDate BETWEEN r.ResponsibleStartDate AND r.ResponsibleEndtDate
),
"most_recent_key" AS (
SELECT
ServiceDate,
ClientId,
MAX(ResponsibleStartDate) AS "ResponsibleStartDate"
FROM all_services
GROUP BY ServiceDate, ClientId
)
SELECT Id, ServiceDate, Hours, ClientId, ClientName, ResponsibleName
FROM all_services
INNER JOIN most_recent_key
USING (ServiceDate, ClientId, ResponsibleStartDate)
Posting it anyway as a contrast to Aaron's better solution as a learning point for myself.

What can I add to my query to total up two rows?

I have the below query and results. What can I add to this query to combine the calories for people with the same name? For example, Dave's total should be 3045+3129 to show 6174.
SELECT
likes.*, beer.cal, (beer.cal * 21) AS 'Drink 3 in a Week'
FROM
likes
INNER JOIN
beer ON likes.beer = beer.beer;
**name beer cal Drink 3 in a Week**
dave bud 145 3045
dave coors 149 3129
gary miller 143 3003
linda coors 149 3129
mike bud 145 3045
mike miller 143 3003
sally coors 149 3129
sally miller 143 3003
You can use window funtion
SELECT
likes.*, beer.cal,
SUM(beer.cal * 21) OVER(PARTITION BY NAME) AS 'Drink 3 in a Week'
FROM
likes
INNER JOIN
beer ON likes.beer = beer.beer;
Another option is group by.

find records with date greater than matching entry in same table

Im trying to find records from a specific records start date forward. Im not sure how to do this. Example
Name Issue Open Date Issue Close Date
John Doe 02/01/2017 02/15/2017
John Doe 02/25/2017 03/01/2017
John Doe 03/05/2017 03/15/2017
John Doe 03/20/2017 03/25/2017
Jane Doe 02/01/2017 02/20/2017
Jane Doe 02/22/2017 02/28/2017
Jane Doe 03/07/2017 03/22/2017
Jane Doe 03/25/2017 04/05/2017
Jim Jones 02/17/2017 02/25/2017
Jim Jones 02/15/2017 02/18/2017
Jim Jones 03/01/2017 03/07/2017
Jim Jones 03/19/2017 04/02/2017
I want to find each record from the first issue close date and forward, but the dates are scattered. So for John Doe, I want to pull back records from 02/15/17 and greater. For Jane Doe I want to pull back records from 02/20/17 and greater. and for Jim Jones I want to pull back records from 02/25/2017 and greater. I need to pull back records starting from a specific date, but I cant just say where issue close date > 02/01/2017 because I don't always know the close date and the date is scattered. thanks
You will need to perform some level of aggregation and store the results in either a CTE or temp table before you can use the first issue close date as a filter. For example:
;WITH CTE AS (
SELECT Name
,min([Issue Close Date]) as FirstIssueCloseDate
FROM yourtable
GROUP BY Name)
SELECT *
FROM yourtable A
JOIN CTE B on a.name = b.name and a.[Issue Open Date] <=
b.FirstIssueCloseDate

Compute sum of hours/day with overlapping periods, SQL

I have a table with the start date(event.startdate), end date(event.enddate), and the hours/person (event.hrday) of an event. I have another table with weekdays listed which has another field for each person (calendar.name). I want to populate those columns with the total hours worked each day. I can't seem to figure out how to properly sum the hours if two events overlap in dates, I can only come up with a correct value for a single event in a time period.
I believe that in theory this question has the answer I need: compute sum of values associated with overlapping date ranges
But I am very new to SQL and I don't fundamentally understand the solution posted even after some additional research. I am using Access 2013. Apologies if this is a super elementary question, I was hoping what I wanted to do could be handled "visually" with Access...
What I Have: ("event" table)
Startdate | Enddate | Hrsday | Name
5/1/2015 5/12/2015 1.25 Joe
5/7/2015 5/8/2015 8 Joe
What I'm looking for:("calendar" table, days already filled in first column)
Weekdays | Joe | name2 | name3 | ....
5/1/2015 1.25
5/4/2015 1.25
5/5/2015 1.25
5/6/2015 1.25
5/7/2015 9.25
5/8/2015 9.25
5/11/2015 1.25
5/12/2015 1.25
I've tried using the query builder within access to build an UPDATE query, but my result either does not appear at all (no updates, all null) or will only fill in one event with no overlaps. (5/1-5/12 all have 1.25).
I think you will need to create a "date table" if you want to be able to achieve this sort of result in MS-Access (without using windowed functions).
Here is a quick example of how this might work in SQL Server, but only using syntax available to MS-Access (I hope).
--Load the test data into a table variable
DECLARE #event TABLE (
[start_date] DATE,
end_date DATE,
hrsperday NUMERIC(19,2),
name VARCHAR(20));
INSERT INTO #event SELECT '20150401', '20150412', 1.25, 'Joe';
INSERT INTO #event SELECT '20150407', '20150408', 8, 'Joe';
--Add some more test data, to make it more "interesting"
INSERT INTO #event SELECT '20150401', '20150405', 0.1, 'Bill';
INSERT INTO #event SELECT '20150401', '20150430', 7.5, 'Bill';
INSERT INTO #event SELECT '20150412', '20150415', 0.5, 'Bill';
--Make a date table, this creates one on the fly but wouldn't work in MS-Access
--I store a date for each day in 2015/Apr, obviously I would want more dates eventually
DECLARE #dates TABLE (
[date] DATE);
WITH cte AS (
SELECT CONVERT(DATE, '20150401') AS [date]
UNION ALL
SELECT DATEADD(DAY, 1, [date]) FROM cte WHERE [date] < '20150430')
INSERT INTO
#dates
SELECT
[date]
FROM
cte OPTION (MAXRECURSION 0);
--Now the answer is trivial
SELECT
e.name,
d.[date],
SUM(hrsperday) AS hrs
FROM
#dates d
LEFT JOIN #event e ON d.[date] BETWEEN e.[start_date] AND e.end_date
GROUP BY
e.name,
d.[date]
ORDER BY
e.name,
d.[date];
--Note the format you want, but a PIVOT would give you this
--(I don't think PIVOT is supported by MS-Access though)
Results for this are:
name date hrs
Bill 2015-04-01 7.60
Bill 2015-04-02 7.60
Bill 2015-04-03 7.60
Bill 2015-04-04 7.60
Bill 2015-04-05 7.60
Bill 2015-04-06 7.50
Bill 2015-04-07 7.50
Bill 2015-04-08 7.50
Bill 2015-04-09 7.50
Bill 2015-04-10 7.50
Bill 2015-04-11 7.50
Bill 2015-04-12 8.00
Bill 2015-04-13 8.00
Bill 2015-04-14 8.00
Bill 2015-04-15 8.00
Bill 2015-04-16 7.50
Bill 2015-04-17 7.50
Bill 2015-04-18 7.50
Bill 2015-04-19 7.50
Bill 2015-04-20 7.50
Bill 2015-04-21 7.50
Bill 2015-04-22 7.50
Bill 2015-04-23 7.50
Bill 2015-04-24 7.50
Bill 2015-04-25 7.50
Bill 2015-04-26 7.50
Bill 2015-04-27 7.50
Bill 2015-04-28 7.50
Bill 2015-04-29 7.50
Bill 2015-04-30 7.50
Joe 2015-04-01 1.25
Joe 2015-04-02 1.25
Joe 2015-04-03 1.25
Joe 2015-04-04 1.25
Joe 2015-04-05 1.25
Joe 2015-04-06 1.25
Joe 2015-04-07 9.25
Joe 2015-04-08 9.25
Joe 2015-04-09 1.25
Joe 2015-04-10 1.25
Joe 2015-04-11 1.25
Joe 2015-04-12 1.25

How to number records based on values

I have the following data
FieldA FieldB FieldC FieldD
1234 01/05/14 Mark John
3234 05/04/2014 Mark Smith
3232 05/09/2013 Kara Sidney
3554 06/08/2012 Lamar Angela
5668 01/01/2011 Kara Rick
I have 15 Million Similar records in a data set.
I would like to create a query that would give unique numbers to "Mark, Kara, Lamar" whenever they appear to be their unique number.
FieldA FieldB FieldC FieldD FieldE
1234 01/05/14 Mark John 1
3234 05/04/2014 Mark Smith 1
3232 05/09/2013 Kara Sidney 2
3554 06/08/2012 Lamar Angela 3
5668 01/01/2011 Kara Rick 2
how can I do that?
If you really want to get crazy, here's a solution:
SELECT [FieldA], [FieldB], a.[FieldC], [FieldD], [FieldE]
FROM [TABLE] a
LEFT JOIN(
SELECT DISTINCT [FieldC], pwdencrypt([FieldC]) as [FieldE]
FROM [TABLE]) b
ON a.[FieldC] = b.[FieldC]
That pwdencrypt() creates a very unique id.