问题
In this question @GordonLinoff provided a solution (recursive common table expression) to my initial question. This is a follow-up question.
Initial question:
How can I loop through registrations until a certain amount (sum) of AmountPersons was reached and if the next AmountPersons was too high to be invited check the AmountPersons of the next row to see if it would fit?
Please check the initial question via the link above to get the full picture.
New situation:
First we have 20 available seats and we run through the data rows to fill these seats (initial question).
Then I sorted on Count_Invited and updated the order by
from the row_number()
function. So people who were invited the least should get priority.
Then I also added the Count_Registered column, because people who registered most, but got invited least, should also get priority.
New question:
How can I scramble the last two people who are invited from the below result if a third, forth, fifth.. user also has the same values (Count_Invited and Count_Registered and AmountPersons are 1)?
The top data is ordered correctly, but only for the last few rows it would need to randomize the invitee.
I know of this ORDER BY NEWID()
functionality to randomize rows, but it can't be applied on all rows in my case. I don't know how to approach this... More info below.
The new T-SQL code:
WITH tn AS (
SELECT g.[Id],
g.[FirstName],
g.[LastName],
g.[E-mail],
g.[Count_Invited],
g.[Count_Registered],
r.[DateReservation],
r.[AmountPersons],
row_number() over(order by g.[Count_Invited], g.[Count_Registered] DESC) as seqnum
FROM USERTABLE g
INNER JOIN RESERVATION r ON r.[UserId] = g.[Id]
WHERE r.[PartyId] = 21
),
cte AS (
SELECT [Id], [FirstName], [LastName], [E-mail], [Count_Invited], [Count_Registered], [DateReservation],
[AmountPersons], [AmountPersons] as total, 1 as is_included, seqnum
FROM tn
WHERE seqnum = 1
UNION ALL
SELECT tn.[Id], tn.[FirstName], tn.[LastName], tn.[E-mail], tn.[Count_Invited], tn.[Count_Registered], tn.[DateReservation], tn.[AmountPersons],
(case when tn.[AmountPersons] +cte.total <= 20
then tn.[AmountPersons] +cte.total
else cte.total
end),
(case when tn.[AmountPersons] +cte.total <= 20
then 1
else 0
end) as is_included,
tn.seqnum
FROM cte join
tn
on tn.seqnum = cte.seqnum + 1
WHERE cte.total < 20
)
SELECT cte.Id AS userId,
cte.FirstName,
cte.LastName,
cte.[E-mail],
cte.Count_Invited,
cte.Count_Registered,
cte.AmountPersons,
cte.DateReservation
FROM cte
WHERE is_included = 1
This is the result I'm getting every time I execute the above code:
I hope this makes sense to someone. Thank you.
Output from suggested answer by @George Menoutis:
Edit: Extra clarification steps. This is what should happen:
-- declare amountSeats = 25
-- select 1st value of Count_Invited
-- if that value is 0
-- do sum of AmountPersons (multiple rows) where Count_Invited is 0
-- if that sum is lower than amountSeats, let's say it's 10 now
-- insert all rows with value 0 in temp table (not sure if this is the way to go...)
-- select 2nd value (not second row) of Count_Invited --> so where Count_Invited is not 0
-- if that value is 1
-- do sum of AmountPersons (multiple rows) where Count_Invited is 1
-- sum count of Count_Invited = 0 + Count_Invited = 1
-- if that sum is still lower then amountSeats, let's say it's 15 now
-- insert (add) all rows with Count_Invited 1 in temp table
-- select 3rd value (not 3rd row) of Count_Invited --> so where Count_Invited NOT IN (0, 1)
-- if that value is 5
-- do count of AmountPersons (multiple rows) where Count_Invited is 5
-- sum count of Count_Invited = 0 + Count_Invited = 1 + Count_Invited = 5
-- let's now say the count for AmountPersons is now 40
-- this means that not everyone with Count_Invited = 5 can be invited as there are only 10 open seats
-- a random selection needs to be made of these rows
-- select random rows where Count_Invited is 5 until the sum of these rows is 10
-- if 10 can't be matched, get as close as possible by looping through the leftover rows, but don't exceed 10
回答1:
I actually think your newid()
idea is best. It's just that the correct way to put it is in the definition of seqnum:
row_number() over(order by g.[Count_Invited], g.[Count_Registered] DESC, newid() asc) as seqnum
Addendum: After OP's comment, I made a new question here. So, it seems that it will work out but you will have to make tn
a temp table first, else newid() is triggered multiple times by the following cte.
来源:https://stackoverflow.com/questions/62292675/randomize-part-of-select-from-cte-output