Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过SQL查询随机获取N行,这将与不同部分中的行总数成比例_Sql_Sql Server - Fatal编程技术网

通过SQL查询随机获取N行,这将与不同部分中的行总数成比例

通过SQL查询随机获取N行,这将与不同部分中的行总数成比例,sql,sql-server,Sql,Sql Server,我有一张表格,上面有很多问题,每个问题都属于一个部分: Id Question SectionId 1 What is ... 3 2 Who is... 3 3 When is... 2 4 Why is... 1 5 How is... 3 大约有1000个问题,大约50个部分。但是,我的查询很简单,例如,我从特定部分的表中选择给定数量的问题 SELEC

我有一张表格,上面有很多问题,每个问题都属于一个部分:

Id      Question        SectionId
 1      What is ...     3
 2      Who is...       3
 3      When is...      2
 4      Why is...       1
 5      How is...       3
大约有1000个问题,大约50个部分。但是,我的查询很简单,例如,我从特定部分的表中选择给定数量的问题

SELECT TOP 10 [Id], [Question] FROM [Questions] 
WHERE [SectionId] IN (1,2)
ORDER BY NEWID()
这很简单,工作也很好,只是有时候我会从一个只有6个问题的部分的10个问题中得到5个问题,从一个有100个问题的部分得到2个问题,从一个有20个问题的部分得到3个问题

如何使结果与每个部分的问题数量成比例。例如,如果我提出10个问题,我会从问题较多的部分获得更多的问题,而从问题较少的部分获得较少的问题

目前我唯一能想到的是进行多个查询,首先一个查询得到每个部分的问题数量,然后做一些数学运算,确定每个部分的问题数量,然后再进行一些查询以获得我想要的问题数量。这听起来很紧张,我希望有一个更实际的方法


注意:SQL查询或EF Linq查询可以工作。

我想不出一种方法可以在一个步骤中完成这项工作,除非您事先知道每个部分的数量和比例

如果必须在查询时计算这些值,则需要运行一个查询以获取部分和比例,并使用该部分和比例构建动态SQL查询

使用GROUP BY查询获取各部分ID和每个部分中的问题数,并按要包含的部分进行筛选

迭代该结果以构建一个动态的UNION ALL查询,该查询获取一个前n,根据每个部分的部分计数/问题总数的百分比计算n,每个部分一个查询,这样您就可以动态构建如下内容:

SELECT TOP 5 ID, Question --because SectionID 1 is 50% of the questions
FROM Questions
WHERE SectionID=1
ORDER BY NEWID()
UNION ALL 
SELECT TOP 3 ID, Question  --because SectionID 2 is 30% of the questions
FROM Questions
WHERE SectionID=2
ORDER BY NEWID()
UNION ALL 
SELECT TOP 2 ID, Question  --because SectionID 3 is 20% of the questions
FROM Questions
WHERE SectionID=3
ORDER BY NEWID()
您可以考虑的另一种方法是创建一个人工排名列,该列由该部分的相对密度作为系数

我的意思是,比如说超级简化,假设第一节是75%的问题,第二节是25%

您将使用行号,按SectionID分区,按NEWID排序并进行分解,以便:

第1节将有1、2、3、5、6、7等值,每4个基数值中有3个

第2节的值为1、5、9、10等,每4节中有1个


然后通过这个人工列对查询结果进行排序。

我想不出一种方法可以在一个步骤中完成这项工作,除非您事先知道每个部分的数量和比例

如果必须在查询时计算这些值,则需要运行一个查询以获取部分和比例,并使用该部分和比例构建动态SQL查询

使用GROUP BY查询获取各部分ID和每个部分中的问题数,并按要包含的部分进行筛选

迭代该结果以构建一个动态的UNION ALL查询,该查询获取一个前n,根据每个部分的部分计数/问题总数的百分比计算n,每个部分一个查询,这样您就可以动态构建如下内容:

SELECT TOP 5 ID, Question --because SectionID 1 is 50% of the questions
FROM Questions
WHERE SectionID=1
ORDER BY NEWID()
UNION ALL 
SELECT TOP 3 ID, Question  --because SectionID 2 is 30% of the questions
FROM Questions
WHERE SectionID=2
ORDER BY NEWID()
UNION ALL 
SELECT TOP 2 ID, Question  --because SectionID 3 is 20% of the questions
FROM Questions
WHERE SectionID=3
ORDER BY NEWID()
您可以考虑的另一种方法是创建一个人工排名列,该列由该部分的相对密度作为系数

我的意思是,比如说超级简化,假设第一节是75%的问题,第二节是25%

您将使用行号,按SectionID分区,按NEWID排序并进行分解,以便:

第1节将有1、2、3、5、6、7等值,每4个基数值中有3个

第2节的值为1、5、9、10等,每4节中有1个


然后按此人工列对查询结果进行排序。

对于分层样本,在排序中进行第n个样本。这有点棘手,但应该可以:

SELECT TOP (10) q.*
FROM (SELECT q.*,
             ROW_NUMBER() OVER (ORDER BY section, NEWID()) as seqnum,
             COUNT(*) OVER (ORDER BY section, NEWID()) as cnt
      FROM [Questions] q
      WHERE [SectionId] IN (1, 2)
     ) q
ORDER BY seqnum % (cnt / 10);

这个逻辑可能有一些边界条件,但随着问题数量的增加和样本的足够大,它应该满足您的要求。

对于分层样本,在排序上进行第n个样本。这有点棘手,但应该可以:

SELECT TOP (10) q.*
FROM (SELECT q.*,
             ROW_NUMBER() OVER (ORDER BY section, NEWID()) as seqnum,
             COUNT(*) OVER (ORDER BY section, NEWID()) as cnt
      FROM [Questions] q
      WHERE [SectionId] IN (1, 2)
     ) q
ORDER BY seqnum % (cnt / 10);

此逻辑可能有一些边界条件,但随着问题数量的增加和样本的足够大,它应该可以满足您的要求。

在没有样本数据的情况下,这是未经测试的,但是,类似的方法可能会起作用:

WITH CTE AS(
    SELECT ID,
           Question,
           SectionID,
           ROW_NUMBER() OVER (ORDER BY NEWID()) AS RN,
           (COUNT(ID) OVER (PARTITION BY SectionID) / (COUNT(ID) OVER () *1.0)) *10 AS Perc 
    FROM YourTable
)
SELECT TOP 10
       ID,
       Question,
       SectionID
FROM CTE
WHERE RN <= CEILING(Perc)
ORDER BY RN ASC;

在缺少样本数据的情况下,这是未经测试的,但是,类似的方法可能会起作用:

WITH CTE AS(
    SELECT ID,
           Question,
           SectionID,
           ROW_NUMBER() OVER (ORDER BY NEWID()) AS RN,
           (COUNT(ID) OVER (PARTITION BY SectionID) / (COUNT(ID) OVER () *1.0)) *10 AS Perc 
    FROM YourTable
)
SELECT TOP 10
       ID,
       Question,
       SectionID
FROM CTE
WHERE RN <= CEILING(Perc)
ORDER BY RN ASC;

您可以使用以下选项在任何部分中始终选择10%的记录:

SELECT TOP ( select CAST(( COUNT(*) * 0.1 ) AS INT ) 
FROM QUESTION WHERE SECTIONID IN ( 1,2)) * FROM QUESTION 
WHERE [SectionId] IN (1,2)
ORDER BY NEWID()

您可以使用以下选项在任何部分中始终选择10%的记录:

SELECT TOP ( select CAST(( COUNT(*) * 0.1 ) AS INT ) 
FROM QUESTION WHERE SECTIONID IN ( 1,2)) * FROM QUESTION 
WHERE [SectionId] IN (1,2)
ORDER BY NEWID()

另一种选择,例如…返回每个部分总行数的20%

DECLARE @percentage numeric(10,2)

SET @percentage = 0.20 --20% of total question for section

SELECT [SectionID],[ID],[Question]
FROM (  SELECT
            [ID],
            [Question],
            [SectionID],
            ROW_NUMBER() OVER(PARTITION BY SectionID ORDER BY NEWID()) [idx],
            COUNT(1) OVER(PARTITION BY SectionID) * @percentage AS [Proportional]
        FROM [Questions]) tbl
WHERE 
    (tbl.[SectionID] = 1 AND tbl.[idx] <= [Proportional])
OR (tbl.[SectionID] = 2 AND tbl.[idx] <= [Proportional])
OR (tbl.[SectionID] = 3 AND tbl.[idx] <= [Proportional])

另一种选择,例如…返回每个部分总行数的20%

DECLARE @percentage numeric(10,2)

SET @percentage = 0.20 --20% of total question for section

SELECT [SectionID],[ID],[Question]
FROM (  SELECT
            [ID],
            [Question],
            [SectionID],
            ROW_NUMBER() OVER(PARTITION BY SectionID ORDER BY NEWID()) [idx],
            COUNT(1) OVER(PARTITION BY SectionID) * @percentage AS [Proportional]
        FROM [Questions]) tbl
WHERE 
    (tbl.[SectionID] = 1 AND tbl.[idx] <= [Proportional])
OR (tbl.[SectionID] = 2 AND tbl.[idx] <= [Proportional])
OR (tbl.[SectionID] = 3 AND tbl.[idx] <= [Proportional])
您可以使用NTILE100F 函数以及over子句按节划分以获得

SELECT TOP 10 [Id], [Question] FROM [Questions] 
WHERE [SectionId] IN (1,2)
ORDER BY NEWID()
应该是

declare @limit int = 10;

;with data as (
   SELECT NTILE(100) over (partition by sectionid ORDER BY NEWID() ) as Centile, [Id], [Question] 
   FROM [Questions] 
   WHERE [SectionId] IN (1,2)
)
select * from data where centile <= @limit

您可以使用NTIL100函数以及over子句分区来获得

SELECT TOP 10 [Id], [Question] FROM [Questions] 
WHERE [SectionId] IN (1,2)
ORDER BY NEWID()
应该是

declare @limit int = 10;

;with data as (
   SELECT NTILE(100) over (partition by sectionid ORDER BY NEWID() ) as Centile, [Id], [Question] 
   FROM [Questions] 
   WHERE [SectionId] IN (1,2)
)
select * from data where centile <= @limit
如何使结果与每个部分的问题数量成比例。冒着陈述显而易见的风险,随机N行不是这个意思。这是一种观察,而不是批评。我怎样才能使结果和每个部分的问题数量“成比例”。冒着陈述显而易见的风险,随机N行不是这个意思。这是观察,不是批评。即使所选部分有问题,也会不断给我零除错误。@Him。我按条件颠倒了顺序。当然,这要求您至少有10行。即使选定的部分有问题,也会不断给我零除错误。@Him。我按条件颠倒了顺序。当然,这要求您至少有10行。