为子孙后代记录所有等级,我们每人只使用1个等级,所以差距是可以的。很抱歉重新提出这个问题,但想问一个关于语法的快速问题。这个解决方案对我们有效(谢谢!)。TSQL中的dt()是什么?但是您想要的是最小值(行数)而不是最大值?另外,假设你不需要特殊人物的行号

为子孙后代记录所有等级,我们每人只使用1个等级,所以差距是可以的。很抱歉重新提出这个问题,但想问一个关于语法的快速问题。这个解决方案对我们有效(谢谢!)。TSQL中的dt()是什么?但是您想要的是最小值(行数)而不是最大值?另外,假设你不需要特殊人物的行号,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,为子孙后代记录所有等级,我们每人只使用1个等级,所以差距是可以的。很抱歉重新提出这个问题,但想问一个关于语法的快速问题。这个解决方案对我们有效(谢谢!)。TSQL中的dt()是什么?但是您想要的是最小值(行数)而不是最大值?另外,假设你不需要特殊人物的行号详细信息,只需要最小结果这确实符合我最初的要求-我最终会使用Sean的答案,因为我们确实需要“临时”数字(不仅仅是最小值或最大值),但我喜欢另一种方法。如果你想要所有的数字,请删除MIN()函数和group by子句,与其他答案相同,这些关系不


为子孙后代记录所有等级,我们每人只使用1个等级,所以差距是可以的。很抱歉重新提出这个问题,但想问一个关于语法的快速问题。这个解决方案对我们有效(谢谢!)。TSQL中的dt()是什么?但是您想要的是最小值(行数)而不是最大值?另外,假设你不需要特殊人物的行号详细信息,只需要最小结果这确实符合我最初的要求-我最终会使用Sean的答案,因为我们确实需要“临时”数字(不仅仅是最小值或最大值),但我喜欢另一种方法。如果你想要所有的数字,请删除
MIN()
函数和
group by
子句,与其他答案相同,这些关系不会导致问题吗?难道不能有三个人拥有同样的灵魂吗?@shawnt00,可以有很多特殊的人拥有同样的灵魂。如果有一个特殊的人,它可以拥有与普通人相同的等级。如果有5个特别的人,他们都可以偶然拥有同样的心灵,和普通人一样。要正确地解决这类任务,如果没有这些联系,整个方法应该是不同的。@shawnt00,正确的解决方案是这样的。让我们有
O
普通人加
S
特殊人。每个普通人有一次机会,每个特殊的人有三次机会。我们应该生成均匀分布在
[1..O+S*3]
范围内的
O
S*3
随机数,然后根据得到的数字对所有人进行排序。特殊人物将在这个有序列表中出现3次,普通人只出现一次。我同意你的第二个评论。但是,您只能有三个具有相同MinRN的表,因为您只加入了这三个表。@shawnt00,我在答案中添加了第二个(正确的)变体。
SELECT personID, ROW_NUMBER()
OVER(ORDER BY NEWID()) as RowNumber
FROM folks
personID    isSpecial
1           1
2           0
3           0
4           0
5           0
6           0
7           0
8           0
9           0
10          0
SELECT personID, isSpecial, row_number
OVER(ORDER BY NEWID()) as RowNumber
FROM folks

personID    RowNumber    isSpecial
8           1            0
2           2            0
10          3            0
1           4            1
9           5            0
3           6            0
4           7            0
6           8            0
5           9            0
7           10            0
personID    MinRowNumber isSpecial rowNumber1 rowNumber2 rowNumber3
8           1            0         1
2           2            0         2
1           3            1         4          7          3
9           5            0         5
3           6            0         6
6           8            0         8
5           9            0         9
7           10           0         10
4           11           0         11         
10          12           0         12
SELECT personID, ROW_NUMBER()
    OVER(ORDER BY NEWID()) as RowNumber
FROM folks
WHERE isSpecial = 0

UNION ALL

SELECT personID, MAX(RN)
FROM (    
    SELECT personID, ROW_NUMBER() AS 'RN'
        OVER(ORDER BY NEWID()) as RowNumber
    FROM folks
    WHERE isSpecial = 1

    UNION ALL

    SELECT personID, ROW_NUMBER()
        OVER(ORDER BY NEWID()) as RowNumber
    FROM folks
    WHERE isSpecial = 1

    UNION ALL

    SELECT personID, ROW_NUMBER()
        OVER(ORDER BY NEWID()) as RowNumber
    FROM folks
    WHERE isSpecial = 1    
    )
GROUP BY personID
WITH
cteTally(N) AS (select n from (values (1),(2),(3))dt(n))

select personID
    , MAX(RowNumber)
from 
(
    SELECT personID
        , ROW_NUMBER() OVER(ORDER BY NEWID()) as RowNumber
    FROM folks f
    join cteTally t on t.N <= case when f.IsSpecial = 1 then 3 else 1 end
) x
group by x.personID
WITH
cteTally(N) AS (select n from (values (1),(2),(3))dt(n))

SELECT personID
    , ROW_NUMBER() OVER(ORDER BY NEWID()) as RowNumber
FROM folks f
join cteTally t on t.N <= case when f.IsSpecial = 1 then 3 else 1 end
create table folks (personID int, isSpecial int)

insert into folks values (1,1);
insert into folks values (2,0);
insert into folks values (3,0);
insert into folks values (4,0);
insert into folks values (5,0);
insert into folks values (6,0);
insert into folks values (7,0);
insert into folks values (8,0);
insert into folks values (9,0);
insert into folks values (10,0);

select * from folks;

select
   personID,
   min(rownumber) as min_rownumber
from
  (SELECT 
      personID, 
      ROW_NUMBER() OVER(ORDER BY NEWID()) as RowNumber
   FROM 
      (select personID from folks 
      union all
      select personID from folks where isSpecial = 1 
      union all
      select personID from folks where isSpecial = 1) u
   ) r
group by
   personID
WITH
CTE_Numbers
AS
(
    SELECT Number
    FROM (VALUES (1),(2),(3)) AS N(Number)
)
,CTE
AS
(
    -- list ordinary people only once
    SELECT PersonID,IsSpecial
    FROM @T
    WHERE IsSpecial = 0

    UNION ALL

    -- list each special person three times
    SELECT PersonID,IsSpecial
    FROM @T CROSS JOIN CTE_Numbers
    WHERE IsSpecial = 1
)
,CTE_rn
AS
(
    SELECT
        PersonID,IsSpecial
        ,ROW_NUMBER() OVER(ORDER BY CRYPT_GEN_RANDOM(4)) AS rn
    FROM CTE
)
SELECT
    PersonID,IsSpecial
    ,MIN(rn) AS FinalRank
FROM CTE_rn
GROUP BY PersonID,IsSpecial
ORDER BY FinalRank;
PersonID    IsSpecial    FinalRank
9           0            1
2           0            2
1           1            3
10          0            4
8           0            5
5           0            6
3           0            7
7           0            9
4           0            10
6           0            12
DECLARE @T TABLE (PersonID int, IsSpecial bit);

INSERT INTO @T(PersonID, IsSpecial) VALUES
(1 , 1),
(2 , 0),
(3 , 0),
(4 , 0),
(5 , 0),
(6 , 0),
(7 , 0),
(8 , 0),
(9 , 0),
(10, 0);

WITH
CTE1
AS
(
    SELECT PersonID, IsSpecial,
        ROW_NUMBER() OVER(ORDER BY CRYPT_GEN_RANDOM(4)) AS rn
    FROM @T
)
,CTE2
AS
(
    SELECT PersonID, IsSpecial,
        ROW_NUMBER() OVER(ORDER BY CRYPT_GEN_RANDOM(4)) AS rn
    FROM @T
)
,CTE3
AS
(
    SELECT PersonID, IsSpecial,
        ROW_NUMBER() OVER(ORDER BY CRYPT_GEN_RANDOM(4)) AS rn
    FROM @T
)
,CTE_All
AS
(
SELECT
    CTE1.PersonID
    ,CTE1.IsSpecial
    ,CTE1.rn AS rn1
    ,CTE2.rn AS rn2
    ,CTE3.rn AS rn3
    ,CA.MinRN
FROM
    CTE1
    INNER JOIN CTE2 ON CTE2.PersonID = CTE1.PersonID
    INNER JOIN CTE3 ON CTE3.PersonID = CTE1.PersonID
    CROSS APPLY
    (
        SELECT MIN(A.rn) AS MinRN
        FROM (VALUES (CTE1.rn), (CTE2.rn), (CTE3.rn)) AS A(rn)
    ) AS CA
)
SELECT
    PersonID
    ,IsSpecial
    ,CASE WHEN IsSpecial = 0 
    THEN rn1 -- a person is not special, he gets random rank from the first run only
    ELSE MinRN -- a special person, he gets a rank that is minimum of three runs
    END AS FinalRank
    ,rn1
    ,rn2
    ,rn3
    ,MinRN
FROM CTE_All
ORDER BY FinalRank;
PersonID    IsSpecial    FinalRank    rn1    rn2    rn3    MinRN
8           0            1            1      1      1      1
6           0            2            2      7      2      2
5           0            3            3      5      6      3
1           1            3            9      3      4      3
4           0            4            4      6      3      3
7           0            5            5      9      10     5
3           0            6            6      8      9      6
2           0            7            7      2      8      2
10          0            8            8      10     5      5
9           0            10           10     4      7      4