Delta of values in same table over time - SQL Server - sql-server

I have a table of data as below in SQL Server:
+-------+------------+-------------------------+--------------------------+
| ID | IP | Date | NumFails |
+-------+------------+-------------------------+--------------------------+
| 21365 | 172.16.2.1 | 2016-05-16 00:20:54.000 | 200 |
| 21457 | 172.16.3.1 | 2016-05-16 00:21:05.000 | 295 |
| 21478 | 172.16.4.1 | 2016-05-16 00:22:46.000 | 128 |
| 24255 | 172.16.2.1 | 2016-05-16 12:22:01.000 | 213 |
| 24318 | 172.16.3.1 | 2016-05-16 12:22:12.000 | 297 |
| 24366 | 172.16.4.1 | 2016-05-16 12:23:52.000 | 243 |
| 25699 | 172.16.2.1 | 2016-05-16 18:21:31.000 | 226 |
| 25794 | 172.16.3.1 | 2016-05-16 18:21:41.000 | 347 |
| 25811 | 172.16.4.1 | 2016-05-16 18:22:51.000 | 270 |
| 27142 | 172.16.2.1 | 2016-05-17 00:22:45.000 | 227 |
| 27193 | 172.16.3.1 | 2016-05-17 00:22:55.000 | 347 |
| 27251 | 172.16.4.1 | 2016-05-17 00:23:59.000 | 270 |
+-------+------------+-------------------------+--------------------------+
I have an idea of how to do this programmatically, but I'm too new to SQL to know how to do this: I want to get the delta of NumFails given a specific time period. For this, I want to be able to do a query that:
Selects IP address from time period A (<2016-05-17 01:00:00.000 and >2016-05-17 00:00:00.000) and matching IP address from time period B (<2016-05-16 01:00:00.000 and >2016-05-16 00:00:00.000) and returns IP address and the difference from period A numfails result MINUS period b numfails result. This is done for every unique IP address in time period A (all are unique) comparing against time period B.
Any easy way to do such a thing? I want to run the report on a daily basis, so period A will shift to today's date, and period B will be the previous day's date. I can pre-populate that with the calling SQL, but I have no clue what to build to grab the two values and do the difference and report.

This solution assumes each IP will exist in both timeframes.
declare #StartPeriodA datetime
declare #EndPeriodA datetime
declare #StartPeriodB datetime
declare #EndPeriodB datetime
set #StartPeriodA = '2016-05-17 00:00:00.000'
set #EndPeriodA = '2016-05-17 01:00:00.000'
set #StartPeriodB = '2016-05-16 00:00:00.000'
set #EndPeriodB = '2016-05-16 01:00:00.000'
select a.IP, a.PeriodAFailures - b.PeriodBFailures as 'FailureDifference'
from
(
select IP, sum(NumFails) as PeriodAFailures
from YourTable
where Date between #StartPeriodA and #EndPeriodA
group by IP
) a
inner join
(
select IP, sum(NumFails) as PeriodBFailures
from YourTable
where Date between #StartPeriodB and #EndPeriodB
group by IP
) b on a.IP = b.IP
You can manipulate the dates as needed.

Related

How to generate IDs based on column values

I will provide examples and code where I can. Assume everything except [CycleStart] and [CycleEnd] datatypes are Varchar, I'm not too fussed about this at this stage.
Table A consists of the following RAW sample data:
+-------+---------+----------------+------------+------------+
| JobID | JobName | CycleDesc | CycleStart | CycleEnd |
+-------+---------+----------------+------------+------------+
| 10003 | Run1 | January 2019 | 31/12/2018 | 31/12/2018 |
| 10005 | Run2 | December 2018 | 31/12/2017 | 31/11/2018 |
| 10006 | Run3 | March 2019 | 31/12/2018 | 31/02/2019 |
| 10007 | Run4 | September 2019 | 31/12/2018 | 31/09/2019 |
| 10008 | Run5 | November 2019 | 31/12/2018 | 31/10/2019 |
+-------+---------+----------------+------------+------------+
Table B consists of the following sample data and the code used to generate this data is below:
+-------+---------+---------+
| JobID | PeriodID | Entity |
+-------+---------+---------+
| 10003 | 202101 | XYZ1 |
| 10003 | 202112 | XYZ2 |
| 10007 | 202008 | XYZ3 |
| 10007 | 202003 | XYZ4 |
| 10008 | 201904 | XYZ5 |
+-------+----------+--------+
Declare #Counter3 INT
SELECT #Counter3=1
WHILE #Counter3 <= 1000
BEGIN
INSERT INTO [dbo].[TableB]
SELECT
FLOOR(RAND()*(33979-1+1))+1 [JobID]
,CAST(ROUND(((2021 - 2019 -1) * RAND() + 2020), 0) AS VARCHAR) + RIGHT('0'+CAST(FLOOR(RAND()*(12-1+1))+1 AS VARCHAR),2) [PeriodID]
,FLOOR(RAND()*(23396-1+1))+1 [Entity]
The issue lies within Table B column [PeriodID]. This column represents an ID generated from [CycleStart] in Table A e.g. 31/12/2018 = 201812 (YYYYMM).
What I want to show in Table B is a Period ID for each Job ID but show EACH month + 30 years ahead of the [CycleStart] date. Example table of what I am looking to achieve:
+-------+---------+---------+
| JobID | PeriodID | Entity |
+-------+---------+---------+
| 10006 | 201812 | XYZ1 |
| 10006 | 201901 | XYZ2 |
| 10006 | 201902 | XYZ3 |
| 10006 | 201903 | XYZ4 |
| 10006 | 201904 | XYZ5 |
| 10006 | 201905 | XYZ5 |
| 10006 | 201906 | XYZ5 |
| 10006 | 201907 | XYZ5 |
| ... | +30yrs | ... |
| 10006 | 204812 | XYZ5 |
+-------+----------+--------+
How can I achieve this? Currently I am just randomly generating IDs which is not related to the [CycleStart] date and therefore just skewing my data but this is the only way I can think of doing it.
The best way is to create a calendar table / date dimension. You can use this table to solve this issue, and reuse it for other problems later. (Search online for some examples on how to build one).
If you have this table then you only need to join this table and that's it.
e.g.
INSERT INTO TableB ( JobID , PeriodID)
SELECT DISTINCT A.JobID , D.TheYear * 100 + D.TheMonth
FROM tableA A
JOIN myDateTable D
ON D.TheDate BETWEEN CONVERT(date , A.CycleStart , 103) AND DATEADD(YEAR,30, CONVERT(date , A.CycleStart , 103));

How to sort rows when sequence order does not match datetime order?

I am trying to sessionize event data and found a case that breaks my query.
I have about 1300 machines that generate about 250k events per day. Each machine reports an EventCode, SequenceNumber ( 0 to 255 ), DateTime ( accurate to the second ), InAmount, OutAmount, RoundsCount.
My current code uses the LEAD(), LAG() functions ordering by DateTime to determine when a session starts and ends. The issue I have found is sometimes the SequenceNumber is not in order vs the DateTime field.
Example data
> +-----------+----------------+---------------------+----------+-----------+-------------+
> | EventCode | SequenceNumber | DateTime | InAmount | OutAmount | RoundsCount |
> +-----------+----------------+---------------------+----------+-----------+-------------+
> | 10051300 | 198 | 2019-06-25 15:22:54 | 16779000 | 14814642 | 142483 |
> | 10000100 | 182 | 2019-06-25 15:22:58 | 16770950 | 14809091 | 142321 |
> | 10000901 | 200 | 2019-06-25 15:23:05 | 16779000 | 14814642 | 142483 |
> | 13328100 | 201 | 2019-06-25 15:23:05 | 16779000 | 14814642 | 142483 |
> | 13328500 | 202 | 2019-06-25 15:23:05 | 16779000 | 14814642 | 142483 |
> | 10003505 | 199 | 2019-06-25 15:23:10 | 16779000 | 14814642 | 142483 |
> | 10003503 | 204 | 2019-06-25 15:23:56 | 16779000 | 14814642 | 142483 |
> +-----------+----------------+---------------------+----------+-----------+-------------+
SequenceNumber 182 and 199 are out of order when the data is ORDER BY DateTime.
I need to sort the data using the SequenceNumber, except the SequenceNumber goes from 0 to 255 multiple times per day and not every number is reported.

Days between status change in SQL Server

I need find the number of days between status change in SQL Server 2014.
For example, please see the data below
+--------+--------+------------+-------------+
| status | Number | updated_on | opened_at |
+--------+--------+------------+-------------+
| Draft | 100 | 2017-11-03 | 2017-11-03 |
| Draft | 100 | 2017-12-12 | 2017-11-03 |
| WIP | 100 | 2017-12-12 | 2017-11-03 |
| Appr | 100 | 2018-01-05 | 2017-11-03 |
| Launch | 100 | 2018-01-10 | 2017-11-03 |
| Close | 100 | 2018-01-11 | 2017-11-03 |
+--------+--------+------------+-------------+
Based on the above input, I need to get
Draft --- 40 days,
WIP --- 23 days,
appro -- 5 days,
deploy/launch - 1 days,
closed --- 69 days
Please help me with SQL query to arrive this results.
Thanks.
I don't think your numbers are right. But this should do what you want, assuming that the statuses are unique:
select status,
datediff(day, updated_on, lead(updated_on) over (order by updated_on) ) as days
from t;
I don't understand the first and last numbers, though.
Try this
SELECT
tb.status,
DATEDIFF(dayofyear, tb.opened_at, tb.LastUpdate) AS DaysInDifference
FROM
(
SELECT
DISTINCT
status,
Max(updated_on) OVER(PARTITION BY [status] )LastUpdate,
opened_at
FROM Table1
)AS tb

Get record between two date from multiple tables in SQL server

I am looking to get records from following two tables
if there does not exist a record in Eligibility for the Participant SSN and EIN in the Transaction where ServiceDate of Transaction is within BenefitEffectiveDate and GracePeriodEndDate.
there can be multiple records for same participant in eligibility table with different plan period for a given Participant SSN and EIN .
for example in below script there are two records for participantSSN = 645075498 in eligibility table and both record has different BenefitEffectiveDate and GracePeriodEndDate, from this table we have to take minimum BenefitEffectiveDate and maximum GracePeriodEndDate. that means for this participant minimum date is 2015-01-01 and maximum date is 2018-01-01
Now in transaction table I have same participantSSN = 645075498 which has has transaction date is 2016-02-10 which is fall between minimum BenefitEffectiveDate and maximum GracePeriodEndDate in eligibility table for participantSSN = 645075498
I want to get record in my output for participantSSN = 645075498
How can I achieve it? so far I have written below query which is not giving me participantSSN = 645075498 in output result.
This is my expected result
| Tid | TPAId | EIN | ParticipantSSN | ParticipantFirstName | ParticipantLastName | TPAParentTransactionId | TPATransactionId | ServiceDate | TransactionDate | Amt |
| 118 | PayFlex | 54401 | 852258852 | GABRIEL | BRYANT | 45758201 | 55277801 | 2016-01-01 | 2016-01-02 | 15 |
| 124 | PayFlex | 54407 | 420145857 | CAROLYN | WOMAC | 45758207 | 55277807 | 2016-03-15 | 2016-03-15 | 60 |
| 125 | PayFlex | 54408 | 345658570 | THOMAS | FAVELA | 45758208 | 55277808 | 2016-03-16 | 2016-03-18 | 60 |
| 126 | PayFlex | 54409 | 541575015 | BETTY | DAVIS | 45758209 | 55277809 | 2016-03-17 | 2016-03-20 | 60 |
| 127 | PayFlex | 54410 | 541575015 | BETTY | DAVIS | 45758209 | 55277809 | 2016-03-17 | 2016-03-20 | 60 |
| 128 | PayFlex | 54409 | 541575015 | BETTY | DAVIS | 45758210 | 55277809 | 2016-03-17 | 2016-03-20 | 60 |
| 129 | PayFlex | 54409 | 541575016 | MANDY | THOMPSON | 45758211 | 55277810 | 2016-03-18 | 2016-03-20 | 80 |
| 130 | PayFlex | 54409 | 541575018 | FRANCIS | GRAYER | 45758212 | 55277811 | 2016-03-19 | 2016-03-22 | 79 |
| 122 | PayFlex | 54405 | 645075498 | MARY | WILSON | 45758205 | 55277805 | 2016-02-07 | 2016-02-10 | 100 |
My Current SQL query
SELECT ParticipantFirstName, ServiceDate, *
FROM DebitCardTransaction d
WHERE NOT EXISTS
(
SELECT 1
FROM Eligibility e
WHERE e.TPAId = d.TPAId
AND e.EIN = d.EIN
AND e.ParticipantSSN = d.ParticipantSSN
AND d.ServiceDate BETWEEN BenefitEffectiveDate AND GracePeriodEndDate
)
Above it my current query and below is sample create table and insert sample data script
CREATE TABLE Eligibility(
EligibilityId INTEGER PRIMARY KEY
,TPAId VARCHAR(7)
,EIN INTEGER
,SubscriberId INTEGER
,ParticipantFirstName VARCHAR(9)
,ParticipantLastName VARCHAR(9)
,ParticipantSSN INTEGER
,BenefitEffectiveDate DATE
,GracePeriodEndDate DATE
);
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (227,'PayFlex',54406,15857506,'TIM','HOPE',138764141,'1/1/2016','2/2/2017');
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (228,'PayFlex',54401,15857501,'BRIEL','BRYANT',852258851,'1/1/2016','2/2/2017');
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (229,'PayFlex',54402,15857502,'LISA','PEREZ',292225757,'1/1/2016','2/2/2017');
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (230,'PayFlex',54403,15857503,'ALEXANDER','JEFFERSON',643035714,'1/1/2016','2/2/2017');
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (231,'PayFlex',54404,15857504,'SHIRLEY','PEREZ',458250578,'1/1/2016','2/2/2017');
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (232,'PayFlex',54405,15857505,'MARY','WILSON',645075498,'1/1/2015','2/2/2016');
INSERT INTO Eligibility(EligibilityId,TPAId,EIN,SubscriberId,ParticipantFirstName,ParticipantLastName,ParticipantSSN,BenefitEffectiveDate,GracePeriodEndDate) VALUES (233,'PayFlex',54405,15857505,'MARY','WILSON',645075498,'1/1/2016','2/2/2018');
CREATE TABLE DebitCardTransaction(
Tid INTEGER PRIMARY KEY
,TPAId VARCHAR(7)
,EIN INTEGER
,ParticipantSSN INTEGER
,ParticipantFirstName VARCHAR(9)
,ParticipantLastName VARCHAR(9)
,TPAParentTransactionId INTEGER
,TPATransactionId INTEGER
,ServiceDate DATE
,TransactionDate DATE
,Amt INTEGER
);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (118,'PayFlex',54401,852258852,'GABRIEL','BRYANT',45758201,55277801,'1/1/2016','1/2/2016',15);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (119,'PayFlex',54402,292225757,'LISA','PEREZ',45758202,55277802,'2/1/2016','2/2/2016',50);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (120,'PayFlex',54403,643035714,'ALEXANDER','JEFFERSON',45758203,55277803,'2/2/2016','2/3/2016',50);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (121,'PayFlex',54404,458250578,'SHIRLEY','PEREZ',45758204,55277804,'2/3/2016','2/5/2016',50);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (122,'PayFlex',54405,645075498,'MARY','WILSON',45758205,55277805,'2/7/2016','2/10/2016',100);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (123,'PayFlex',54406,138764141,'TIM','HOPE',45758206,55277806,'2/10/2016','2/11/2016',110);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (124,'PayFlex',54407,420145857,'CAROLYN','WOMAC',45758207,55277807,'3/15/2016','3/15/2016',60);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (125,'PayFlex',54408,345658570,'THOMAS','FAVELA',45758208,55277808,'3/16/2016','3/18/2016',60);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (126,'PayFlex',54409,541575015,'BETTY','DAVIS',45758209,55277809,'3/17/2016','3/20/2016',60);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (127,'PayFlex',54410,541575015,'BETTY','DAVIS',45758209,55277809,'3/17/2016','3/20/2016',60);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (128,'PayFlex',54409,541575015,'BETTY','DAVIS',45758210,55277809,'3/17/2016','3/20/2016',60);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (129,'PayFlex',54409,541575016,'MANDY','THOMPSON',45758211,55277810,'3/18/2016','3/20/2016',80);
INSERT INTO DebitCardTransaction(Tid,TPAId,EIN,ParticipantSSN,ParticipantFirstName,ParticipantLastName,TPAParentTransactionId,TPATransactionId,ServiceDate,TransactionDate,Amt) VALUES (130,'PayFlex',54409,541575018,'FRANCIS','GRAYER',45758212,55277811,'3/19/2016','3/22/2016',79);
I think this is what you're after;
SELECT
d.Tid
,d.TPAId
,d.EIN
,d.ParticipantSSN
,d.ParticipantFirstName
,d.ParticipantLastName
,d.TPAParentTransactionId
,d.TPATransactionId
FROM DebitCardTransaction d
LEFT JOIN (SELECT ParticipantSSN, MIN(BenefitEffectiveDate) BenefitEffectiveDate, MAX(GracePeriodEndDate) GracePeriodEndDate FROM #Eligibility GROUP BY ParticipantSSN) e
ON d.ParticipantSSN = e.ParticipantSSN
AND d.TransactionDate BETWEEN e.BenefitEffectiveDate AND e.GracePeriodEndDate
WHERE e.ParticipantSSN IS NULL OR d.ParticipantSSN = 645075498
ORDER BY d.Tid
It gives the result set that you've asked except for Tid 122 (Mary Wilson), which doesn't meet the criteria as I understand them.

Group by Date bigger than SQL Server

I'm working with Micrososft SqlServer 2012 and I have this table:
Table
+-----------+--------+------------+
| Id_Client | Amount | Date |
+-----------+--------+------------+
| 1 | 100 | 24/08/2015 |
| 2 | 100 | 24/07/2015 |
| 3 | 100 | 24/06/2015 |
| 3 | 100 | 24/05/2015 |
+-----------+--------+------------+
And I need to make a query like this:
Query
SELECT ID_CLIENT,
CASE WHEN DATE <= '01/07/2015' THEN 'OLD' ELSE 'NEW' END,
SUM(AMOUNT) FROM TABLE
GROUP BY ID_CLIENT
How do I Group by Date with the condition, instead of each Date?
I expect something like:
Expected result
+---+-----+-----+
| 1 | NEW | 100 |
| 2 | NEW | 100 |
| 3 | OLD | 200 |
+---+-----+-----+

Resources