Fabrice's weblog

Tools and Source

News


Read sample chapters or buy LINQ in Action now!
Our LINQ book is also available on AMAZON

.NET jobs

Emplois .NET

The views expressed on this weblog are mine alone and do not necessarily reflect the views of my employer. The content of this weblog is independent from Microsoft or any other company. transatlantys hot news

Contact

Me

Others

Selected content

Randomizing LINQ to SQL queries

Yesterday, a developer asked in the LINQ in Action forum and in Microsoft's official LINQ forum how to write a LINQ to SQL query that would return random records from the database.

It's not something built-in. There is no Random query operator provided by Microsoft. In addition, it can't be done simply by using the System.Random class, because everything in a LINQ to SQL query must be translatable to SQL.

Jim replied with several options:

  • Use a pass-through query to get the results
  • Use a view to return the ID of the record from tblImages from your subselect and map to that view. Then use a LINQ query to join the tblProperties through the Randomize view and then to the tblImages
  • Use a scalar TSQL Function to get a random picture and include that in your LINQ query.
  • Use a stored procedure to return the results.

As Jim points out, we discuss consuming pass-through queries, functions and stored procedures in chapter 8 of LINQ in Action.

Let's detail the solution that uses a SQL user-defined function. The most common way to sort records randomly is to use the NEWID SQL Server function. This is what this solution uses.

First, create the following view:

CREATE VIEW RandomView
AS
SELECT NEWID() As ID

Then create the following function that uses the view:

CREATE FUNCTION GetNewId
(
)
RETURNS uniqueidentifier
AS
BEGIN
RETURN (SELECT ID FROM RandomView)
END

The view is required because it's not possible to directly use NEWID in a scalar function.

You can then map the GetNewId user-defined function using LINQ to SQL's Function attribute. Again, see chapter 8 for the details.

That's it! You can now write LINQ queries as usual. Here is an example to pick a random object:

var tool = db.Tools.OrderBy(t => db.GetNewId()).First()

Here is another example that uses GetNewId to sort results randomly: 

var tools =
  from tool in db.Tools
  orderby db.GetNewId()
  select tool.Name;


Cross-posted from http://linqinaction.net

Comments

AndrewSeven said:

Would using Guid.NewGuid() work?

var tools =

 from tool in db.Tools

 orderby Guid.NewGuid()

 select tool.Name;

# January 9, 2008 9:51 PM

Fabrice Marguerie said:

Good question! I'll give it a try and see if LINQ to SQL translates this to SQL.

# January 10, 2008 4:42 AM

Fabrice Marguerie said:

Andrew, I tested, and no ORDER BY clause is generated at all in SQL for the query you suggest.

# January 11, 2008 5:39 PM

Cecile said:

Hi,

I've found that the following works for getting a random record:

IEnumerable<Class> Query = db.ExecuteQuery<Class>(@"select top 1 ID from Table order by NewID()");

The only problem is that it only returns IEnumerable. I'm too lazy at the moment to try to figure out how to cast this to IQueryable. This lets me do what I need at the moment anyway.

FYI, I'm new to C# and Linq, so I appreciate all the help I get from blogs like yours.

# January 30, 2008 4:56 PM

Atomiton said:

You're essentially doing the same thing Cecile... The difference is that what Fabrice is doing enables you to to do Random Sorting, random Selection... all within LINQ.  You're essentially just writing SQL instead of letting LINQ do the work for you.  For Simple Queries you should try to use LINQ as it will optimize it very well.  For complex queries use db.ExecuteQuery.

# March 1, 2008 6:08 AM

Cecile said:

Atomiton, thanks for the tip. I ended up using db.ExecuteQuery because that was what came up in the VS documentation when I first searched for how to query a database. Also, I posted that query as an alternative to creating a view. To be honest, I don't know enough about C# (and even less about Linq) to make suggestions on the most optimal statements.

# March 5, 2008 8:59 PM

Scott Brickey said:

The problem with using NewID (not that there's much alternative) is that for large collections, SQL Server must generate random GUIDs for EVERY RECORD in the table, then SORT the results by this (remember it's in memory, not indexed!).

Other solutions I've seen attempt to use some sort of hash mark or calculation (for auto-incrementing counters, not GUIDs) to quickly retrieve one out of many.

I think the solution used at a previous employer was a sproc that would pick a random (integer-based-counter) between MIN and MAX, then test that the record exists... in a simple loop (yes ugly) it would always return a valid result. I don't believe it looped for more than 2 or 3 iterations for the majority of calls.

Best of luck,

-Scott

# April 8, 2008 2:53 PM

CCook's Blog said:

Randomizing LINQ Queries

# August 29, 2008 10:36 PM

foreign currency trading said:

A new generation of virtual land speculators and developers along the lines of IwantOneOfThose. com will emerge from the eBay and Amazon communities as the corporations integrate their infrastructures- new uses of virtual currencies will play a huge role

# September 22, 2008 5:41 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)