Getting multiple records on year wise - sql

I have a Patient information table with ~50 million records. I need to check some samples for each year which may be in any order. Here are the sample date available in database "20090722", "20080817", ... "19980301". Also i have a primary-key column called "PID". My requirement is to get 2 or 3 samples for each year with a query.
I tried to get 2 samples for each year using sub-queries, i am not succeeded.
Any one in this forum have idea on this kind of requirement, If so please help me.
Guys i tried the following query in sql server and it worked find. But i need the query in MYSQL. Please help me out.
select pid,studydate
FROM (SELECT ROW_NUMBER() OVER ( PARTITION BY studydate ORDER BY pid DESC ) AS
'RowNumber', pid,studydate
FROM patient
) pt
WHERE RowNumber <= 2

If I understand you correctly you could do something like this:
select year(datecolumn) as Year,
(select id from PatiendRecords pr2 where pr2.id>=min(pr.id)+rand()*max(pr.id) LIMIT 1),
(select id from PatiendRecords pr2 where pr2.id>=min(pr.id)+rand()*max(pr.id) LIMIT 1),
(select id from PatiendRecords pr2 where pr2.id>=min(pr.id)+rand()*max(pr.id) LIMIT 1)
from PatiendRecords pr
group by year(datecolumn);
EDIT
delimiter //
CREATE PROCEDURE RandomRecordsPerYear(n INT)
BEGIN
CREATE TEMPORARY TABLE lookup
(id INT) ENGINE = MEMORY;
SET #x = 0;
REPEAT SET #x = #x + 1;
INSERT INTO lookup (id)
SELECT (SELECT id FROM PatientRecords pr WHERE pr2.id>=min(pr.id)+rand()*max(pr.id) LIMIT 1) AS Id FROM PatientRecords pr GROUP BY year(created_at);
UNTIL #x >= n END REPEAT;
SELECT * FROM PatientRecords s JOIN lookup l ON l.id=pr.id;
DROP TABLE lookup;
END
//
call RandomRecordsPerYear(3)//
PS. I find it pretty cool that you have 50 million patient records in a MySQL database. DS.

SELECT md.*
FROM (
SELECT #r := #r + 1 AS y
FROM (
#r := 0
) vars
CROSS JOIN
mytable
LIMIT 200
) years
JOIN mytable md
ON md.datecol >= CAST('1900-01-01' AS DATETIME) + INTERVAL y YEARS
AND md.datecol < CAST('1900-01-01' AS DATETIME) + INTERVAL y + 1 YEARS
AND md.id <=
COALESCE(
(
SELECT id
FROM mytable mi
WHERE mi.datecol >= CAST('1900-01-01' AS DATETIME) + INTERVAL y YEARS
AND mi.datecol < CAST('1900-01-01' AS DATETIME) + INTERVAL y + 1 YEARS
ORDER BY
id
LIMIT 2
), 0xFFFFFFFF)

Related

Finding the Difference of Two Results

I have two results with two different dates (a recent one and the previous one) the numbers below are the result 250 being the most recent and 300 being the previous result:
250
300
The code I use is here:
SELECT TOP 2
MY FIELD as bmi
FROM
MY TABLE
ORDER BY
THE DATE FIELD DESC
Within this same code I want to be able to find the difference between those two numbers and for that to appear not the two numbers?
I have tried a few things of skipping N rows etc but now I don't know what I can do?
I think you want something like this:
declare #firstBmiRes int
declare #secondBmiRes int
SET #firstBmiRes = 250 /* insert your query */
SET #secondBmiRes = 300 /* insert your query */
(SELECT SUM(#secondBmiRes - #firstBmiRes))
If you want to continue to use the calculated result. You can obviously store the value into another variable like this:
declare #bmi int
SET #bmi = (SELECT SUM(#secondBmiRes - #firstBmiRes))
SELECT #bmi
2nd Approach:
Since we don't have very much information to work with. you could try something like this... But i'm assuming a lot of your datastructure here.
declare #BmiScore int
declare #firstBmiRes int
declare #secondBmiRes int
SET #firstBmiRes = (SELECT TOP 1 MY_FIELD
FROM MY_TABLE
ORDER BY DATE_FIELD DESC)
SET #secondBmiRes = (SELECT MY_FIELD
FROM MY_TABLE
ORDER BY DATE_FIELD DESC
OFFSET 1 ROW
FETCH NEXT 1 ROW ONLY)
SET #bmiScore = (SELECT SUM(#secondBmiRes - #firstBmiRes))
SELECT #bmiScore
SELECT
MYFIELD - LAG (MYFIELD,1) OVER (ORDER BY MYDATE) AS BMI
FROM
MYTABLE;
ORDER BY MYDATE DESC
Using a LEAD function if you want your code to be a part of new code for some reason:
select TOP 1 (bmi - lead(bmi) over (order by date_field)) as result
from( SELECT TOP 2 my_field as bmi
, date_field
FROM my_table
ORDER BY date_field DESC) A
Here is a DEMO
Or by LAG :
select TOP 1 (lag(my_field) over (order by date_field) - my_field ) as result
FROM my_table
ORDER BY date_field DESC;
You can use LEAD/ LAG if your version of SQL Server supports these functions. If you are on an older version then you can use a windowed function to apply an order to the rows.
Here's your data going into a temporary table variable:
DECLARE #MY_TABLE TABLE (THE_DATE_FIELD DATE, MY_FIELD INT);
INSERT INTO #MY_TABLE SELECT '20200114', 300 UNION ALL SELECT '20200113', 250;
...and here's a query to perform the calculation you needed:
WITH x AS (
SELECT TOP 2
THE_DATE_FIELD,
MY_FIELD AS bmi,
ROW_NUMBER() OVER (ORDER BY THE_DATE_FIELD DESC) AS order_id
FROM
#MY_TABLE)
SELECT
MAX(CASE WHEN order_id = 1 THEN bmi END) - MAX(CASE WHEN order_id = 2 THEN bmi END) AS difference_bmi
FROM
x;
If I peek at the data from the CTE then I see this (and this is why I included the date field, which is redundant, and could otherwise be removed):
THE_DATE_FIELD bmi order_id
2020-01-14 300 1
2020-01-13 250 2
Now it's simply a case of picking the two values, as one has an order_id = 1 and one has an order_id = 2.

Update record for the last week

I'm building a report that needs to show how many users were upgraded from account status 1 to account status 2 each hour for the last week (and delete hours where the upgrades = 0). My table has an updated date, however it isn't certain that the account status is the item being updated (it could be contact information etc).
The basic table config that I'm working with is below. There are other columns but they aren't needed for my query.
account_id, account_status, updated_date.
My initial idea was to first filter and look at the data for the current week, then find if they were at account_status = 1 and later account_status = 2.
What's the best way to tackle this?
This is the kind of thing that you would use a SELF JOIN for. It's tough to say exactly how to do this without getting any kind of example data, but hopefully you can build off of this at least. There are a lot of tutorials on how to write a successful self join, so I'd refer to those if you're having difficulties.
select a.account_id
from tableName a, tableName b
where a.account_id= b.account_id
and
(a.DateModified > 'YYYY-MM-DD' and a.account_status = 1)
and
(b.DateModified < 'YYYY-MM-DD' and b.account_status= 2)
Maybe you could try to rank all the updates older than an update, with a status of 2 for an account by the timestamp descending. Check if such an entry with status 1 and rank 1 exists, to know that the respective younger update did change the status from 1 to 2.
SELECT *
FROM elbat t1
WHERE t1.account_status = 2
AND EXISTS (SELECT *
FROM (SELECT rank() OVER (ORDER BY t2.updated_date DESC) r,
t2.account_status
FROM elbat t2
WHERE t2.account_id = t1.account_id
AND t2.updated_date <= t1.updated_date) x
WHERE x.account_status = 1
AND x.r = 1);
Then, to get the hours you, could create a table variable and fill it with the hours worth a week (unless you already have a suitable calender/time table). Then INNER JOIN that table (variable) to the result from above. Since it's an INNER JOIN hours where no status update exists won't be in the result.
DECLARE #current_time datetime = getdate();
DECLARE #current_hour datetime = dateadd(hour,
datepart(hour,
#current_time),
convert(datetime,
convert(date,
#current_time)));
DECLARE #hours
TABLE (hour datetime);
DECLARE #interval_size integer = 7 * 24;
WHILE #interval_size > 0
BEGIN
INSERT INTO #hours
(hour)
VALUES (dateadd(hour,
-1 * #interval_size,
#current_hour));
SET #interval_size = #interval_size - 1;
END;
SELECT *
FROM #hours h
INNER JOIN (SELECT *
FROM elbat t1
WHERE t1.account_status = 2
AND EXISTS (SELECT *
FROM (SELECT rank() OVER (ORDER BY t2.updated_date DESC) r,
t2.account_status
FROM elbat t2
WHERE t2.account_id = t1.account_id
AND t2.updated_date <= t1.updated_date) x
WHERE x.account_status = 1
AND x.r = 1)) y
ON convert(date,
y.updated_date) = h.convert(date,
h.hour)
AND datepart(hour,
y.updated_date) = datepart(hour,
h.hour);
If you use this often and/or performance is important, you might consider to introduce persistent, computed and indexed columns for the convert(...) and datepart(...) expressions and use them in the query instead. Indexing the calender/time table and the columns used in the subqueries is also worth a consideration.
(Disclaimer: Since you didn't provide DDL of the table nor any sample data this is totally untested.)

SQL Query Help - Negative reporting

Perhaps somebody can help with Ideas or a Solution. A User asked me for a negative report. We have a table with tickets each ticket has a ticket number which would be easy to select but the user wants a list of missing tickets between the first and last ticket in the system.
E.g. Select TicketNr from Ticket order by TicketNr
Result
1,
2,
4,
7,
11
But we actually want the result 3,5,6,8,9,10
CREATE TABLE [dbo].[Ticket](
[pknTicketId] [int] IDENTITY(1,1) NOT NULL,
[TicketNr] [int] NULL
) ON [PRIMARY]
GO
SQL Server 2016 - TSQL
Any ideas ?
So a bit more information is need all solution thus far works on small table. Our production database has over 4 million tickets. Hence why we need to find the missing ones.
First get the minimum and maximum, then generate all posible ticket numbers and finally select the ones that are missing.
;WITH FirstAndLast AS
(
SELECT
MinTicketNr = MIN(T.TicketNr),
MaxTicketNr = MAX(T.TicketNr)
FROM
Ticket AS T
),
AllTickets AS
(
SELECT
TicketNr = MinTicketNr,
MaxTicketNr = T.MaxTicketNr
FROM
FirstAndLast AS T
UNION ALL
SELECT
TicketNr = A.TicketNr + 1,
MaxTicketNr = A.MaxTicketNr
FROM
AllTickets AS A
WHERE
A.TicketNr + 1 <= A.MaxTicketNr
)
SELECT
A.TicketNr
FROM
AllTickets AS A
WHERE
NOT EXISTS (
SELECT
'missing ticket'
FROM
Ticket AS T
WHERE
A.TicketNr = T.TicketNr)
ORDER BY
A.TicketNr
OPTION
(MAXRECURSION 32000)
If you can accept the results in a different format, the following will do what you want:
select TicketNr + 1 as first_missing,
next_TicketNr - 1 as last_missing,
(next_TicketNr - TicketNr - 1) as num_missing
from (select t.*, lead(TicketNr) over (order by TicketNr) as next_TicketNr
from Ticket t
) t
where next_TicketNr <> TicketNr + 1;
This shows each sequence of missing ticket numbers on a single row, rather than a separate row for each of them.
If you do use a recursive CTE, I would recommend doing it only for the missing tickets:
with cte as (
select (TicketNr + 1) as missing_TicketNr
from (select t.*, lead(TicketNr) over (order by TicketNr) as next_ticketNr
from tickets t
) t
where next_TicketNr <> TicketNr + 1
union all
select missing_TicketNr + 1
from cte
where not exists (select 1 from tickets t2 where t2.TicketNr = cte.missing_TicketNr + 1)
)
select *
from cte;
This version starts with the list of missing ticket numbers. It then adds a new one, as the numbers are not found.
One method is to use recursive cte to find the missing ticket numbers :
with missing as (
select min(TicketNr) as mnt, max(TicketNr) as mxt
from ticket t
union all
select mnt+1, mxt
from missing m
where mnt < mxt
)
select m.*
from missing m
where not exists (select 1 from tickets t where t.TicketNr = m.mnt);
This should do the trick: SQL Fiddle
declare #ticketsTable table (ticketNo int not null)
insert #ticketsTable (ticketNo) values (1),(2),(4),(7),(11)
;with cte1(ticketNo, isMissing, sequenceNo) AS
(
select ticketNo
, 0
, row_number() over (order by ticketNo)
from #ticketsTable
)
, cte2(ticketNo, isMissing, sequenceNo) AS
(
select ticketNo, isMissing, sequenceNo
from cte1
union all
select a.ticketNo + 1
, 1
, a.sequenceNo
from cte2 a
inner join cte1 b
on b.sequenceNo = a.sequenceNo + 1
and b.ticketNo != a.ticketNo + 1
)
select *
from cte2
where isMissing = 1
order by ticketNo
It works by collecting all of the existing tickets, marking them as existing, and assigning each a consecutive number giving their order in the original list.
We can then see the gaps in the list by finding any spots where the consecutive order number shows the next record, but the ticket numbers are not consecutive.
Finally, we recursively fill in the gaps; working from the start of a gap and adding new records until that gap's consecutive numbers no longer has a gap between the related ticket numbers.
I think this one give you easiest solution
with cte as(
select max(TicketNr) maxnum,min(TicketNr) minnum from Ticket )
select a.number FROM master..spt_values a,cte
WHERE Type = 'P' and number < cte.maxnum and number > cte.minno
except
select TicketNr FROM Ticket
So After looking at all the solutions
I went with creating a temp table with a full range of number from Starting to Ending ticket and then select from the Temp table where the ticket number not in the ticket table.
The reason being I kept running in MAXRECURSION problems.

SQL Server 2008 : how to select sum of all sessions where difference between two consecutive sessions is less than 10 minutes

I have a table which stores chat messages for users. Every message is logged in this table. I have to calculate chat duration for a particular user.
Since there is a possibility that user is chatting at x time and after x+10 times he leaves chatting. After X+20 time, again user starts chatting. So the time period between x+10 and x+20 should not be accounted.
Table structure and sample data is as depicted. Different color represent two chat sessions for same user. As we can see that between 663 and 662 there is a difference of more than 1 hour, so such sessions should be excluded from the resultset. Final result should be 2.33 minutes.
declare #messagetime1 as datetime
declare #messagetime2 as datetime
select #messagetime1=messagetime from tbl_chatMessages where ID=662
select #messagetime2=messagetime from tbl_chatMessages where ID=659
print datediff(second,#messagetime2,#messagetime1)
Result --- 97 seconds
declare #messagetime3 as datetime
declare #messagetime4 as datetime
select #messagetime3=messagetime from tbl_chatMessages where ID=668
select #messagetime4=messagetime from tbl_chatMessages where ID=663
print datediff(second,#messagetime4,#messagetime3)
Result -- 43 seconds
Please suggest a solution to calculate duration of chat. This is one of the logic I could think of, in case any one of you has a better idea. Please share with a solution
first need to calculate the gap between adjacent messages, if the gap of more than 600 seconds, so the time between these messages 0
SELECT SUM(o.duration) / 60.00 AS duration
FROM dbo.tbl_chatMessages t1
OUTER APPLY (
SELECT TOP 1
CASE WHEN DATEDIFF(second, t2.messageTime, t1.messageTime) > 600
THEN 0
ELSE DATEDIFF(second, t2.messageTime, t1.messageTime) END
FROM dbo.tbl_chatMessages t2
WHERE t1.messageTime > t2.messageTime
ORDER BY t2.messageTime DESC
) o(duration)
See demo on SQLFiddle
Try something like this:
WITH DATA
AS (SELECT t1.*,
CASE
WHEN
Isnull(Datediff(MI, t2.MESSAGETIME, t1.MESSAGETIME), 11) > 10
THEN 0
ELSE 1
END first_ident
FROM TABLE1 t1
LEFT JOIN TABLE1 t2
ON t1.ID = t2.ID + 1),
CTE
AS (SELECT ID,
MESSAGETIME,
ID gid,
0 AS tot_time
FROM DATA
WHERE FIRST_IDENT = 0
UNION ALL
SELECT t1.ID,
t1.MESSAGETIME,
t2.GID,
t2.TOT_TIME
+ Datediff(MI, t2.MESSAGETIME, t1.MESSAGETIME)
FROM DATA t1
INNER JOIN CTE t2
ON t1.ID = t2.ID + 1
AND t1.FIRST_IDENT = 1)
SELECT GID,
Max(TOT_TIME) Tot_time
FROM CTE
GROUP BY GID
I set up a working example on SQL Fiddle. Take a look and let me know if you have any questions.
Here is the reasoning behind my solution. First, identify each chat that starts a chatting period. You can do this with a flag that identifies a chat that is more than 10 minutes from the previous chat.
Then, take this flag and do a cumulative sum. This sum actually serves as a grouping identifier for the chat periods. Finally, aggregate the results to get the info for each chat period.
with cmflag as (
select cm.*,
(case when datediff(min, prevmessagetime, messagetime) > 10
then 0
else 1
end) as ChatPeriodStartFlag
from (select cm.*,
(select top 1 messagetime
from tbl_chatMessages cm2
where cm2.senderId = cm.senderId or
cm2.RecipientId = cm.senderId
) as prevmessagetme
from tbl_chatMessages cm
) cm
),
cmcum as (
select cm.*,
(select sum(ChatPeriodStartFlag)
from cmflag cmf
where cm2.senderId = cm.senderId or
cm2.RecipientId = cm.senderId and
cmf.messagetime <= cm.messagetime
) as ChatPeriodGroup
from tbl_chatMessages cm
)
select cm.SenderId, ChatPeriodGroup, min(messageTime) as mint, max(messageTime) as maxT
from cmcum
group by cm.SenderId, ChatPeriodGroup;
One challenge that I may not fully understand is how you are matching between senders and recipients. All the rows in your sample data have the same pair. This is looking at the "user" from the SenderId perspective, but takes into account that in a chat period, the user could be either the sender or recipient.
You could use this query (here):
DECLARE #Results TABLE(
RowNum INT NOT NULL,
senderID INT NOT NULL DEFAULT(80),
recipientID INT NOT NULL DEFAULT(79),
PRIMARY KEY(RowNum,senderID,recipientID),
messageTime DATETIME NOT NULL
);
INSERT INTO #Results(RowNum,senderID,recipientID,messageTime)
SELECT ROW_NUMBER() OVER(PARTITION BY senderID,recipientID ORDER BY messageTime, ID) AS RowNum,
c.senderID,c.recipientID,c.messageTime
FROM dbo.tbl_chatMessages c;
WITH RecursiveCTE
AS(
SELECT crt.RowNum,crt.senderID,crt.recipientID,
crt.messageTime,
1 AS SessionID
FROM #Results crt
WHERE crt.RowNum=1
UNION ALL
SELECT crt.RowNum,crt.senderID,crt.recipientID,
crt.messageTime,
CASE
WHEN DATEDIFF(MINUTE,prev.messageTime,crt.messageTime) <= 10 THEN prev.SessionID
ELSE prev.SessionID+1
END
FROM #Results crt INNER JOIN RecursiveCTE prev ON crt.RowNum=prev.RowNum+1
AND crt.senderID=prev.senderID
AND crt.recipientID=prev.recipientID
)
SELECT *,
STUFF(CONVERT(VARCHAR(8), DATEADD(SECOND,x.SessionDuration,0), 114), 1,3,'') AS SessionDuration_mmss,
SUM(x.SessionDuration) OVER() AS SessionDuration_Overall,
STUFF(CONVERT(VARCHAR(8), DATEADD(SECOND,SUM(x.SessionDuration) OVER(),0), 114), 1,3,'') AS SessionDuration_Overall_mmss
FROM(
SELECT r.senderID,r.recipientID,r.SessionID,
DATEDIFF(SECOND, MIN(r.messageTime),MAX(r.messageTime)) AS SessionDuration
FROM RecursiveCTE r
GROUP BY r.senderID,r.recipientID,r.SessionID
) x
OPTION(MAXRECURSION 0);
Results:
senderID recipientID SessionID SessionDuration SessionDuration_mmss SessionDuration_Overall SessionDuration_Overall_mmss
-------- ----------- ----------- --------------- -------------------- ----------------------- ----------------------------
80 79 1 97 01:37 140 02:20
80 79 2 43 00:43 140 02:20
I’d focus on slight modifications in table structure and updating the chat server application code (if possible of course).
Can you have the chat server to generate new chat ID every time there is a delay between messages that is longer than X minutes? If yes then calculating chat duration will become very easy.

Find the longest sequence of a value in a table

This is an SQL Question, I think it is difficult one - I'm not sure it is possible to achieve in a simple SQL sentence or a stored procedure:
I want to find the number of the longest sequence of the same (known) number in a column in a table:
example:
TABLE:
DATE SALEDITEMS
1/1/09 4
1/2/09 3
1/3/09 3
1/4/09 4
1/5/09 3
calling the sp/sentence for 4 will give 1 calling the sp/sentecne for 3 will give 2
as there was 2 times in a row number 3.
I'm running SQL server 2008.
UPDATE: I generated a million rows of random data, and abandoned the recursive CTE solution, as its query plan didn't make good use of indexes in the optimizer.
But the non-recursive solution I originaly posted turned out to work great, as long as there was an additional non-clustered index on (SALEDITEMS, [DATE]). This makes sense, since the query needs to filter in both directions (both by date and by SALEDITEMS). With this additional index, queries on a million rows return in under 2 seconds on my (not very beefy) desktop mathine. Without this index, the query was dog-slow.
BTW, this is a great example of how SQL Server's cost-based query optimization totally breaks down in some cases. The recursive CTE solution has a cost (on my PC) of 42 and takes at least several minutes to finish. The non-recursive solution has a cost of 15,446 (!!!) and completes in 1.5 seconds. Moral of the story: when comparing SQL Server query plans, don't assume that cost necessarily correlates to query performance!
Anyway, here's the solution I'd recommend (the same non-recursive CTE I posted earlier) :
DECLARE #SALEDITEMS INT = 3;
WITH SalesNoMatch ([DATE], SALEDITEMS, NoMatchDate)
AS
(
SELECT [DATE], SALEDITEMS,
(SELECT MIN([DATE]) FROM Sales s2 WHERE s2.SALEDITEMS <> #SALEDITEMS
AND s2.[DATE] > s1.[DATE]) as NoMatchDate
FROM Sales s1
)
, SalesMatchCount ([DATE], ConsecutiveCount) AS
(
SELECT [DATE], 1+(SELECT COUNT(1) FROM Sales s2 WHERE s2.[DATE] > s1.[DATE] AND s2.[DATE] < NoMatchDate)
FROM SalesNoMatch s1
WHERE s1.SALEDITEMS = #SALEDITEMS
)
SELECT MAX(ConsecutiveCount)
FROM SalesMatchCount;
Here's the DDL I used to test this, including indexes you'll need:
CREATE TABLE [Sales](
[DATE] date NOT NULL,
[SALEDITEMS] int NOT NULL
);
CREATE UNIQUE CLUSTERED INDEX IX_Sales ON Sales ([DATE]);
CREATE UNIQUE NONCLUSTERED INDEX IX_Sales2 ON Sales (SALEDITEMS, [DATE]);
And here's how I created my test data-- 1,000,001 rows with ascending dates with SALEDITEMS randomly set between 1 and 10.
INSERT INTO Sales ([DATE], SALEDITEMS)
VALUES ('1/1/09', 5)
DECLARE #i int = 0;
WHILE (#i < 1000000)
BEGIN
INSERT INTO Sales ([DATE], SALEDITEMS)
SELECT DATEADD (d, 1, (SELECT MAX ([DATE]) FROM Sales)), ABS(CHECKSUM(NEWID())) % 10 + 1
SET #i = #i + 1;
END
Here's the recursive-CTE solution that I abandoned:
DECLARE #SALEDITEMS INT = 3;
-- recursive CTE solution (remember to set MAXRECURSION!)
WITH SalesRowNum ([DATE], SALEDITEMS, RowNum)
AS
(
SELECT [DATE], SALEDITEMS, ROW_NUMBER() OVER (ORDER BY s1.[DATE]) as RowNum
FROM Sales s1
)
, SalesCTE (RowNum, [DATE], ConsecutiveCount)
AS
(
SELECT s1.RowNum, s1.[DATE], 1 AS ConsecutiveCount
FROM SalesRowNum s1
WHERE SALEDITEMS = #SALEDITEMS
UNION ALL
SELECT s1.RowNum, s1.[DATE], ConsecutiveCount + 1 AS ConsecutiveCount
FROM SalesRowNum s1
INNER JOIN SalesCTE s2 ON s1.RowNum = s2.RowNum + 1
WHERE SALEDITEMS = #SALEDITEMS
)
SELECT MAX(ConsecutiveCount)
FROM SalesCTE;
Untested, because you did not provide DDL and sample data:
DECLARE #SALEDITEMS INT;
SET #SALEDITEMS=3;
SELECT MAX(cnt) FROM(
SELECT COUNT(*) FROM YourTable JOIN (
SELECT y1.[Date] AS d1, y2.[Date] AS d2
FROM YourTable AS y1 JOIN YourTable AS y2
ON y1.SALEDITEMS=#SALEDITEMS AND y2.SALEDITEMS=#SALEDITEMS
AND NOT EXISTS(SELECT 1 FROM YourTable AS y
WHERE y.SALEDITEMS<>#SALEDITEMS
AND y1.[Date] < y.[Date] AND y.[Date] < y2.[Date])
) AS t
WHERE [Date] BETWEEN t.d1 AND t.d2
) AS t;