Home > Back-end >  T-SQL Random Output of Two Values
T-SQL Random Output of Two Values

Time:11-08

I have a table of users that are owned by various Owners. One person left and the list of users needs to be split up between two owners. How would you use SQL to randomly assign the users between two ownerIds . For example, a function that theoretically behaves like below

UPDATE Users
set OwnerId = RAND(64,72)
Where OwnerId = 37

We are utilizing SQL Server 2012. Tried looking at a random function between two users but is unable to find anything specific. Thank you,

CodePudding user response:

You can use CHECKSUM(NEWID()) which returns an integer that is either odd or even, so then just check mod 2 (% 2).

UPDATE dbo.Users
   SET OwnerId = CASE 
   WHEN CHECKSUM(NEWID()) % 2 = 0 THEN 64 ELSE 72 END
WHERE OwnerId = 37;

Working example in this fiddle.

If you want to be cryptic/clever or play code golf, then something like this can work in this very specific example:

UPDATE dbo.Users 
  SET OwnerId = 64   (CHECKSUM(NEWID()) % 2 * 8)
WHERE OwnerId = 37;

The reason this works better than RAND() is because RAND() is only evaluated once, whereas NEWID() is evaluated for every row.

Following Larnu's recommendation, though, you could also do this:

WITH cte AS
(
  SELECT ID, OwnerId, rn = ROW_NUMBER() OVER (ORDER BY ID)
  FROM dbo.Users
  WHERE OwnerId = 37
)
UPDATE cte SET OwnerId = 64   (rn % 2 * 8);

Working example in this fiddle. This will produce a more even (but perhaps too predictable) distribution, it just can't be exactly even if there are an odd number of existing matching rows.

CodePudding user response:

First let's discuss how to provide example data. One of the better ways is to provide the SQL to define an object and then populate it with data. In your case something like this would use useful:

DECLARE @users TABLE (UserID INT, OwnerID INT)
INSERT INTO @users (UserID, OwnerID) VALUES
(1, 100),(2, 100),(3, 100),(4, 100),(5, 100),(6, 100),(7, 100),(8, 100),(9, 100),(10, 100)

Now we can use that to provide a demo. If you truly want to randomly assign between two users, it's a bit more complicated. To divide the users evenly between two new owners you could do something like this

SELECT *, CASE WHEN UserID % 2 = 0 THEN 101 ELSE 102 END AS NewOwner
  FROM @users

All we're doing here is finding the modulo of the UserID to look for it being 0. If the userID can be evenly divided by 2 then Owner 101 gets the user, otherwise Owner 102 gets them.

UserID  OwnerID NewOwner
------------------------
1       100     102
2       100     101
3       100     102
4       100     101
5       100     102
6       100     101
7       100     102
8       100     101
9       100     102
10      100     101

If you want to split between more users, increase the modulo and provide more WHEN options:

SELECT *, CASE WHEN UserID % 3 = 0 THEN 101 
               WHEN UserID % 3 = 1 THEN 102 
               ELSE 103 END AS NewOwner
  FROM @users
UserID  OwnerID NewOwner
------------------------
1       100     102
2       100     103
3       100     101
4       100     102
5       100     103
6       100     101
7       100     102
8       100     103
9       100     101
10      100     102

To make the split actually random we can leverage the RAND function. This isn't usually random for each row, but we can bully it a bit.

SELECT *, CASE WHEN (ROUND(((3 - 1 -1) * RAND(CAST(NEWID() AS VARBINARY))   1), 0) - 1) = 0 THEN 101 ELSE 102 END AS NewOwner
  FROM @users
UserID  OwnerID NewOwner
1       100     101
2       100     101
3       100     101
4       100     102
5       100     102
6       100     101
7       100     102
8       100     101
9       100     102
10      100     102

We can add additional values like this: (note the extra WHEN and random sequence range increased to 4)

SELECT *, CASE WHEN (ROUND(((4 - 1 -1) * RAND(CAST(NEWID() AS VARBINARY))   1), 0) - 1) = 0 THEN 101
               WHEN (ROUND(((4 - 1 -1) * RAND(CAST(NEWID() AS VARBINARY))   1), 0) - 1) = 1 THEN 102
               ELSE 103 END AS NewOwner
  FROM @users
UserID  OwnerID NewOwner
------------------------
1       100     102
2       100     103
3       100     101
4       100     101
5       100     101
6       100     103
7       100     102
8       100     103
9       100     103
10      100     103
  • Related