【问题标题】:SQL Server - Select N random rows from 2 tablesSQL Server - 从 2 个表中选择 N 个随机行
【发布时间】:2016-06-17 06:34:03
【问题描述】:

我正在尝试从 2 个表中随机选择 N 行。我的第一张桌子是这样的:

q_id | question_text
-----------------
  1  | What am I doing?
  2  | Who are you?
  3  | Hmm?

我要加入的表如下所示:

a_id | q_id | answer_text
-------------------------
  1  |   1  | Nothing
  2  |   1  | Something
  3  |   2  | Mike
  4  |   2  | Steve
  5  |   2  | Jon
  6  |   3  | Yup
  7  |   3  | Nope

我想用他们的答案输出一个随机问题。因此,如果我有 50 行,例如,我可以选择前 3 行,它会输出 3 个随机问题,无论答案有多少。

这是我一直在使用的查询,但是当我使用 TOP(2) 时,它只获取前 2 个答案而不是前 2 个问题:

查询:

SELECT TOP(2) q.q_id, q.question_text, a.answer_text
FROM question q 
INNER JOIN answers a ON q.q_id= a.q_id

当前结果:

2  |  Who are you?  | Mike, Steve

预期结果:

1  | What am I doing? | Nothing, Something
3  | Who are you?     | Mike, Steve, Jon

【问题讨论】:

  • 如果您尝试随机选择问题,为什么要使用TOP?这总是会给你同样的三个问题。
  • 我完全不明白你的问题。您的示例查询将输出 2 行,而不是 1 行,并且 'Nothing, Something' 不在您的 answer_text 的示例值中。
  • 我同意,您实际上是希望每个答案占一行,还是希望每个问题的一行中所有可能答案的串联字符串?
  • 我认为您需要使用 for xml path 将多行合并为一个(对于所有答案),然后使用 a 到 order by newID() 然后您的前 2 个就可以了。
  • 我对你的问题感到困惑。你想要 3 个随机问题,每个问题都有 3 个随机答案吗?如果您从测试库构建测试,这很常见

标签: sql sql-server


【解决方案1】:

这会让你更接近 - 请注意,它不会神奇地用逗号分隔答案并将它们放在一行中,但它至少会给你两个完整的问题。您可以(并且可能应该)在表示层中使用逗号分隔的内容。

  SELECT
    q.q_id,
    q.question_text,
    a.answer_text
  FROM question q
  INNER JOIN answers a ON q.q_id = a.q_id
  WHERE q.q_id IN (SELECT TOP 2 q_id FROM question);

如果您想出一种更随机的方式来指定问题 ID,您可以将其替换为 WHERE q.q_id IN ... 子查询。

【讨论】:

    【解决方案2】:

    有了这个答案,它将在您选择的范围内生成 3 个随机数,选择与这些值关联的问题,然后从答案表中提供具有这些 id 的答案。这个答案的问题在于它可能会产生重复的值。这可以通过联合来解决。

    DECLARE @MIN INT = 1
    DECLARE @MAX INT = 100
    DECLARE @rand1 INT =  (SELECT CAST(((@max-@min-1) * RAND() + @min) AS INT))
    DECLARE @rand2 INT =  (SELECT CAST(((@max-@min-1) * RAND() + @min) AS INT))
    DECLARE @rand3 INT =  (SELECT CAST(((@max-@min-1) * RAND() + @min) AS INT))
    
    SELECT q.question_text, a.answer_text
    FROM question_table q 
    INNER JOIN answer_table a
        ON q.q_id = a.q_id
    WHERE q.q_id IN(@rand1, @rand2, @rand3)
    
    ORDER BY q.q_id, a.a_id
    

    【讨论】:

      【解决方案3】:

      您需要随机问题,然后加入答案。加入答案是微不足道的。要获得随机问题,您可以使用 ID,因为它们是整数,但如果您使用身份,那么它们可能不连续。因此,根据 SQL Server 的版本,可以使用 row_number 函数:

      select q_id
      from
      (select 
        row_number() over(ORDER BY q_id) as Row,
        q_id
      from questions) q
       where Row in ( (select CAST(RAND() * (select COUNT(q_id) from questions) + 1 as int)), 
          (select CAST(RAND() * (select COUNT(q_id) from questions) + 1 as int)))
      

      由于我们要提取两个随机数,因此您应该得到两条记录。然后只需加入即可获取其余数据

      【讨论】:

        【解决方案4】:

        您可以使用newID()选择随机数量的问题,如下:

        declare @n int = 2 --set number of questions here
        
        ;with Question as (select top (@n) * from QuestionTable
                           order by newID())
        
        select * from Question a
        left join AnswerTable b
        on a.q_id = b.q_id
        

        【讨论】:

        • 虽然是“标准”的做法,但强烈不推荐,因为在幕后你为每一行关联一个 GUID,排序可能有很高的成本(CPU、内存和 I/ ○)。考虑阅读以下内容:msdn.microsoft.com/en-us/library/cc441928.aspx
        • 当然,但在这种情况下,所讨论的表听起来相对较小,并且newID 解决方案比使用rand 的建议解决方案更简单、更灵活。由于问题涉及选择可变数量的行,我认为允许轻松调整该变量的解决方案是最合适的。
        猜你喜欢
        • 2010-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-02
        • 1970-01-01
        • 1970-01-01
        • 2018-09-23
        • 1970-01-01
        相关资源
        最近更新 更多