加入一个表从第二个表获取随机行

时间:2011-02-17 15:59:34

标签: tsql sql-server-2008

我有两个表:#tmpParams,列出了29种Disability和Grade的组合。第二个表#tmpSource包含许多具有StudentID,Disability和Grade的学生。我需要从#tmpSource中选择29个随机行,通过Disability and Grade加入#tmpParams。

换句话说,有人向我递交了29名学生(残疾和年级)的参数列表,他们希望29名来自#tmpSource的随机学生,包括StudentID,在这两个领域匹配。

这是DDL:

  IF OBJECT_ID('tempdb..#tmpParams') IS NOT NULL 
        BEGIN
              DROP TABLE #tmpParams
        END
  GO

  IF OBJECT_ID('tempdb..#tmpSource') IS NOT NULL 
        BEGIN
              DROP TABLE #tmpSource
        END
  GO

    /* Create parameter table */
    CREATE TABLE #tmpParams
         ( 
            Disability        varchar(10)
            ,Grade      varchar(10)
         )
    GO        

    /* populate it */
    INSERT INTO #tmpParams
        (Disability, Grade)
    SELECT '13 - AUT' ,'Grade 1'  UNION ALL
    SELECT '08 - SL' ,'Grade 1'  UNION ALL
    SELECT '11 - PSD' ,'Grade 1'  UNION ALL
    SELECT '04 - SLD' ,'Grade 2'  UNION ALL
    SELECT '04 - SLD' ,'Grade 2'  UNION ALL
    SELECT '08 - SL' ,'Grade 2'  UNION ALL
    SELECT '08 - SL' ,'Grade 2'  UNION ALL
    SELECT '08 - SL' ,'Grade 2'  UNION ALL
    SELECT '14 - TBI' ,'Grade 2'  UNION ALL
    SELECT '07 - PD' ,'Grade 2'  UNION ALL
    SELECT '08 - SL' ,'Grade 3'  UNION ALL
    SELECT '08 - SL' ,'Grade 3'  UNION ALL
    SELECT '08 - SL' ,'Grade 3'  UNION ALL
    SELECT '08 - SL' ,'Grade 3'  UNION ALL
    SELECT '08 - SL' ,'Grade 3'  UNION ALL
    SELECT '07 - PD' ,'Grade 3'  UNION ALL
    SELECT '04 - SLD' ,'Grade 4'  UNION ALL
    SELECT '04 - SLD' ,'Grade 4'  UNION ALL
    SELECT '08 - SL' ,'Grade 4'  UNION ALL
    SELECT '08 - SL' ,'Grade 4'  UNION ALL
    SELECT '08 - SL' ,'Grade 4'  UNION ALL
    SELECT '08 - SL' ,'Grade 4'  UNION ALL
    SELECT '08 - SL' ,'Grade 4'  UNION ALL
    SELECT '04 - SLD' ,'Grade 5'  UNION ALL
    SELECT '04 - SLD' ,'Grade 5'  UNION ALL
    SELECT '04 - SLD' ,'Grade 5'  UNION ALL
    SELECT '04 - SLD' ,'Grade 5'  UNION ALL
    SELECT '08 - SL' ,'Grade 5'  UNION ALL
    SELECT '08 - SL' ,'Grade 5';
    GO


    /* Create table to hold source */
    CREATE TABLE #tmpSource
         ( 
            StudentID          int
            ,Disability     varchar(10)
            ,Grade          varchar(10)
         )
    GO 

    INSERT INTO #tmpSource
        (StudentID, Disability, Grade)
    SELECT '3', '04 - SLD', 'Grade 2'  UNION ALL
    SELECT '31', '04 - SLD', 'Grade 2'  UNION ALL
    SELECT '39', '04 - SLD', 'Grade 2'  UNION ALL
    SELECT '46', '04 - SLD', 'Grade 2'  UNION ALL
    SELECT '10', '04 - SLD', 'Grade 4'  UNION ALL
    SELECT '13', '04 - SLD', 'Grade 4'  UNION ALL
    SELECT '25', '04 - SLD', 'Grade 4'  UNION ALL
    SELECT '33', '04 - SLD', 'Grade 4'  UNION ALL
    SELECT '57', '04 - SLD', 'Grade 4'  UNION ALL
    SELECT '60', '04 - SLD', 'Grade 4'  UNION ALL
    SELECT '8', '04 - SLD', 'Grade 5'  UNION ALL
    SELECT '19', '04 - SLD', 'Grade 5'  UNION ALL
    SELECT '23', '04 - SLD', 'Grade 5'  UNION ALL
    SELECT '51', '04 - SLD', 'Grade 5'  UNION ALL
    SELECT '55', '04 - SLD', 'Grade 5'  UNION ALL
    SELECT '16', '07 - PD', 'Grade 2'  UNION ALL
    SELECT '28', '07 - PD', 'Grade 2'  UNION ALL
    SELECT '36', '07 - PD', 'Grade 2'  UNION ALL
    SELECT '43', '07 - PD', 'Grade 2'  UNION ALL
    SELECT '11', '07 - PD', 'Grade 3'  UNION ALL
    SELECT '14', '07 - PD', 'Grade 3'  UNION ALL
    SELECT '26', '07 - PD', 'Grade 3'  UNION ALL
    SELECT '34', '07 - PD', 'Grade 3'  UNION ALL
    SELECT '58', '07 - PD', 'Grade 3'  UNION ALL
    SELECT '61', '07 - PD', 'Grade 3'  UNION ALL
    SELECT '5', '08 - SL', 'Grade 1'  UNION ALL
    SELECT '21', '08 - SL', 'Grade 1'  UNION ALL
    SELECT '41', '08 - SL', 'Grade 1'  UNION ALL
    SELECT '48', '08 - SL', 'Grade 1'  UNION ALL
    SELECT '2', '08 - SL', 'Grade 2'  UNION ALL
    SELECT '30', '08 - SL', 'Grade 2'  UNION ALL
    SELECT '38', '08 - SL', 'Grade 2'  UNION ALL
    SELECT '45', '08 - SL', 'Grade 2'  UNION ALL
    SELECT '12', '08 - SL', 'Grade 3'  UNION ALL
    SELECT '15', '08 - SL', 'Grade 3'  UNION ALL
    SELECT '27', '08 - SL', 'Grade 3'  UNION ALL
    SELECT '35', '08 - SL', 'Grade 3'  UNION ALL
    SELECT '59', '08 - SL', 'Grade 3'  UNION ALL
    SELECT '62', '08 - SL', 'Grade 3'  UNION ALL
    SELECT '9', '08 - SL', 'Grade 4'  UNION ALL
    SELECT '20', '08 - SL', 'Grade 4'  UNION ALL
    SELECT '24', '08 - SL', 'Grade 4'  UNION ALL
    SELECT '52', '08 - SL', 'Grade 4'  UNION ALL
    SELECT '56', '08 - SL', 'Grade 4'  UNION ALL
    SELECT '7', '08 - SL', 'Grade 5'  UNION ALL
    SELECT '18', '08 - SL', 'Grade 5'  UNION ALL
    SELECT '22', '08 - SL', 'Grade 5'  UNION ALL
    SELECT '50', '08 - SL', 'Grade 5'  UNION ALL
    SELECT '54', '08 - SL', 'Grade 5'  UNION ALL
    SELECT '4', '11 - PSD', 'Grade 1'  UNION ALL
    SELECT '32', '11 - PSD', 'Grade 1'  UNION ALL
    SELECT '40', '11 - PSD', 'Grade 1'  UNION ALL
    SELECT '47', '11 - PSD', 'Grade 1'  UNION ALL
    SELECT '6', '13 - AUT', 'Grade 1'  UNION ALL
    SELECT '17', '13 - AUT', 'Grade 1'  UNION ALL
    SELECT '42', '13 - AUT', 'Grade 1'  UNION ALL
    SELECT '49', '13 - AUT', 'Grade 1'  UNION ALL
    SELECT '53', '13 - AUT', 'Grade 1'  UNION ALL
    SELECT '1', '14 - TBI', 'Grade 2'  UNION ALL
    SELECT '29', '14 - TBI', 'Grade 2'  UNION ALL
    SELECT '37', '14 - TBI', 'Grade 2'  UNION ALL
    SELECT '44', '14 - TBI', 'Grade 2';
    GO

将29名学生填入#tmpParams,将62名学生填入#tmpSource。当然,我的现实场景要复杂得多。

我可以轻松地从#tmpSource获得29名随机学生......但是我如何加入#tmpParams以获得在两个领域匹配的29名学生?

   SELECT TOP 29
       TS.StudentID
       ,TS.Disability
       ,TS.Grade
   FROM #tmpSource AS TS
   ORDER BY NEWID();
   GO

一如既往,感谢您的帮助,如果我能澄清某些内容或让您更容易阅读,请告诉我。

3 个答案:

答案 0 :(得分:3)

我可能会遗漏一些东西,但为什么不呢

SELECT TOP 29 TS.StudentID,
              TS.Disability,
              TS.Grade
FROM   #tmpParams P
       JOIN #tmpSource TS
         ON TS.Disability = P.Disability
            AND TS.Grade = P.Grade
ORDER  BY NEWID()

修改

你想要这个吗?

SELECT TS.StudentID,
       TS.Disability,
       TS.Grade
FROM   #tmpParams P
       CROSS APPLY (SELECT TOP 1 *
                    FROM   #tmpSource TS
                    WHERE  TS.Disability = P.Disability
                           AND TS.Grade = P.Grade
                    ORDER  BY NEWID()) TS  

编辑2

你想要这个吗?

 ;WITH T1
     AS (SELECT *,
                Row_number() OVER (PARTITION BY Disability, Grade ORDER BY Newid()) RN
         FROM   #tmpSource),
     T2
     AS (SELECT Disability,
                Grade,
                Row_number() OVER (PARTITION BY Disability, Grade 
                                       ORDER BY (SELECT 0)) AS RN
         FROM   #tmpParams)
SELECT T1.Disability,
       T1.Grade,
       T1.StudentID
FROM   T1
       JOIN T2
         ON T1.Disability = T2.Disability
            AND T2.Grade = T1.Grade
            AND T1.RN = T2.RN  

答案 1 :(得分:2)

with sample as
(
   select p.disability, p.grade, count(*) as numOfSamples from #tmpParams P
   group by p.disability, p.grade
),
rownumedStuds as
(
   select std.id, std.disability, std.grade, row_number() over (partition by std.disability, std.grade order by newID()) num
)
select a.id,a.disability, a.grade 
from sample b
inner join rownumedStuds a on a.grade = b.grade and a.disability = b.disability
where num <= numOfSamples

基本上它确实计算了桶的数量和匹配的数量,然后随机化每个组(如果这是性能很重你可以循环加入它只有rownumedStuds中需要的仅用于随机化你需要的组的类别。

实际选择我希望非常简单

问候 路加

答案 2 :(得分:0)

我可能已经想到了这一点,虽然看起来并不优雅:

 /* Add identity column to #tmpParams */
 ALTER TABLE #tmpParams ADD ID INT IDENTITY (1,1)

 /* drop #tmpResults if exists */
       IF OBJECT_ID('tempdb..#tmpResults') IS NOT NULL 
             BEGIN
                   DROP TABLE #tmpResults
             END
       GO

 /* Create table to hold results */
 CREATE TABLE #tmpResults
  ( 
     StudentID          int
     ,Disability     varchar(10)
     ,Grade          varchar(10)
  )
 GO 

 DECLARE @i AS INT; -- set variable to parse through 
 SET @i = 1
 WHILE @i <= (SELECT MAX(ID) FROM #tmpParams) -- Max number in table
 BEGIN
     INSERT INTO #tmpResults
         SELECT TOP 1
             TS.StudentID
             ,TS.Disability
             ,TS.Grade
         FROM #tmpSource AS TS
         JOIN #tmpParams AS TP
             ON TS.Disability = TP.Disability
             AND TS.Grade = TP.Grade
         WHERE TP.ID = @i 
             AND TS.StudentID NOT IN (SELECT StudentID FROM #tmpResults)  -- so no duplicates
         ORDER BY NEWID()
     SET @i = @i + 1
 END;
 GO

感谢你的帮助,马丁,它让我走上正轨。