Home > Tips N Tricks > Top N Random records from each group

Top N Random records from each group


Problem:

The requirement is to get top 10 employee’s name randomly from each department in a company. Let me elaborate it. Suppose in a company ABC, there are 1500 employees with 5 departments and each department have more than 200 employees. The manager wants to list down at least 10 names of the employees randomly from each department for a survey.

Solution:

In a given [Employees] table with columns [EmployeeName], [DeptName] we have some data, let’s say around 1500 records.


Use the below script to create and populate data in the [Employee] table:

CREATE TABLE [dbo].[Employees](
	[EmployeeName] [varchar](50) NULL,
	[DeptName] [varchar](50) NULL
) ON [PRIMARY]

To populate [Employees] table with dummy data:

DECLARE  @emptemp  TABLE
(
	[EmployeeName]  varchar(50)
	,[DeptName] varchar(50)
)
 
DECLARE @dept int
DECLARE @employee int
SET @dept = 65
SET @employee = 70
 
WHILE @dept < 70
BEGIN
	WHILE @employee < 90
	BEGIN
		INSERT INTO @emptemp
				   ([EmployeeName]
				   ,[DeptName])
			 VALUES( CHAR(@employee), CHAR(@dept) + CHAR(@dept + 1) )
 
		SET @employee = @employee + 1
	END 
 
	SET @employee = 70
	SET @dept = @dept + 1
END   
 
INSERT INTO [dbo].[Employees]
           ([EmployeeName]
           ,[DeptName])
   SELECT [EmployeeName]
           ,[DeptName] from @emptemp
 
select * FROM dbo.Employees

Below are the different ways to get the problem solved:

  • By Using Cursor
/*
The below script will show random 10 records from each department from Employees table.
*/
 
DECLARE @deptColumn varchar(50)
--For creation of a temporary table with no data.
select * into #temporaryT
from dbo.Employees where 1=2
 
DECLARE UserCursor CURSOR for
select distinct DeptName from dbo.Employees
 
OPEN UserCursor
FETCH NEXT FROM UserCursor
INTO @deptColumn
 
WHILE @@FETCH_STATUS = 0
BEGIN
 
	INSERT INTO #temporaryT
	select top 10 * from dbo.Employees where DeptName = @deptColumn
		order by NEWID()  --newid() for random records
 
	FETCH NEXT FROM UserCursor
	INTO @deptColumn
END
 
CLOSE UserCursor
DEALLOCATE UserCursor
 
select * from #temporaryT order by DeptName
DROP TABLE #temporaryT
  • By Using ROW_NUMBER: Here is the short and effective query to do the above operation.
SELECT DeptName,EmployeeName  FROM
(select
ROW_NUMBER() OVER(PARTITION BY DeptName ORDER BY newid() ) AS RowID
, * FROM dbo.Employees ) InnerQ
WHERE InnerQ.RowID <= 10
--RANK() can also be used instead of ROW_NUMBER()
  • By using WITH : another descent code to get the above result set
with distinctDepts as
(SELECT DISTINCT DeptName FROM dbo.Employees)
 
SELECT InnerQ.* FROM distinctDepts  d
CROSS APPLY
(SELECT top 10 * FROM dbo.Employees
	WHERE DeptName = d.DeptName
ORDER BY newid()) InnerQ

Hope these queries will be helpful in pulling down your stress level.

Categories: Tips N Tricks
  1. pranzis
    May 22nd, 2010 at 18:07 | #1

    This is very helpful.

    I wonder if there is a script to generate random valid names? i would be needing this for testing purposes rather than manual data entry. I appreciate your help in this regard. Thanks!

  2. August 13th, 2010 at 19:45 | #2

    Hi Arun
    good to see ur website.

    Its wonderful and it shows ur talent.
    lalit
    UCE-1999 passout
    Electrical

  3. March 8th, 2011 at 17:22 | #3

    Hello pransiz,
    If you have a list of valid first names and last names, you can cross join both ans select in random order to create a random list of names for test data

  4. Dexon
    June 10th, 2011 at 16:15 | #4

    Good, affect the performance behavior required to optimize solution

  5. ravikumar s
    November 10th, 2011 at 18:12 | #5

    Hi arun this is great.
    Here i’m posting one doubt,can you clarify me .

    I have a employee and department tables ,assume that employee table having same fields of oracle emp table like dept also. Now i want to distinct locations whare managers and subordinates are not working at same place (i.e empidmgr id)

    thanks in advance
    Ravikumar s

  1. No trackbacks yet.