Случайная строка от Linq до Sql

Каков наилучший (и самый быстрый) способ получить случайную строку с использованием Linq to SQL, когда у меня есть условие, например. какое-то поле должно быть истинным?

Ответ 1

Вы можете сделать это в базе данных, используя поддельный UDF; в частичном классе добавьте метод в контекст данных:

partial class MyDataContext {
     [Function(Name="NEWID", IsComposable=true)] 
     public Guid Random() 
     { // to prove not used by our C# code... 
         throw new NotImplementedException(); 
     }
}

Тогда просто order by ctx.Random(); это сделает случайный порядок на SQL-сервере любезно NEWID(). то есть.

var cust = (from row in ctx.Customers
           where row.IsActive // your filter
           orderby ctx.Random()
           select row).FirstOrDefault();

Обратите внимание, что это подходит только для таблиц малого и среднего размера; для огромных таблиц это будет иметь влияние производительности на сервере, и будет более эффективным найти количество строк (Count), а затем выбрать один случайным образом (Skip/First).


для подхода подсчета:

var qry = from row in ctx.Customers
          where row.IsActive
          select row;

int count = qry.Count(); // 1st round-trip
int index = new Random().Next(count);

Customer cust = qry.Skip(index).FirstOrDefault(); // 2nd round-trip

Ответ 2

Еще один пример для платформы Entity Framework:

var customers = db.Customers
                  .Where(c => c.IsActive)
                  .OrderBy(c => Guid.NewGuid())
                  .FirstOrDefault();

Это не работает с LINQ to SQL. OrderBy просто отбрасывается.

Ответ 3

EDIT: Я только что заметил, что это LINQ to SQL, а не LINQ to Objects. Используйте код Marc, чтобы получить базу данных для этого. Я оставил этот ответ здесь как потенциальную достопримечательность для LINQ to Objects.

Как ни странно, вам действительно не нужно получать счет. Тем не менее, вам нужно получить каждый элемент, если вы не получите счет.

Что вы можете сделать, так это сохранить идею "текущего" значения и текущего счета. Когда вы получите следующее значение, возьмите случайное число и замените "current" на "new" с вероятностью 1/n, где n - счет.

Итак, когда вы читаете первое значение, вы всегда делаете это "текущее" значение. Когда вы читаете второе значение, вы можете сделать это текущее значение (вероятность 1/2). Когда вы читаете третье значение, вы можете сделать это текущее значение (вероятность 1/3) и т.д. Когда у вас закончились данные, текущее значение является случайным из всех прочитанных с равномерной вероятностью.

Чтобы применить это условие, просто игнорируйте все, что не соответствует этому условию. Самый простой способ сделать это - рассмотреть только последовательность "соответствия" для начала, применяя сначала предложение Where.

Вот быстрая реализация. Я думаю, все в порядке...

public static T RandomElement<T>(this IEnumerable<T> source,
                                 Random rng)
{
    T current = default(T);
    int count = 0;
    foreach (T element in source)
    {
        count++;
        if (rng.Next(count) == 0)
        {
            current = element;
        }            
    }
    if (count == 0)
    {
        throw new InvalidOperationException("Sequence was empty");
    }
    return current;
}

Ответ 4

Одним из способов достижения эффективности является добавление столбца в ваши данные Shuffle, который заполняется случайным int (по мере создания каждой записи).

Частичный запрос для доступа к таблице в случайном порядке...

Random random = new Random();
int seed = random.Next();
result = result.OrderBy(s => (~(s.Shuffle & seed)) & (s.Shuffle | seed)); // ^ seed);

Это выполняет операцию XOR в базе данных и упорядочивает результаты этого XOR.

Преимущества: -

  • Эффективный: SQL обрабатывает заказывать, не нужно брать все таблица
  • Повторяемость: (хорошо для тестирование) - может использовать один и тот же случайный семя для генерации одного и того же случайного заказ

Это подход, используемый моей домашней системой автоматизации для рандомизации плейлистов. Он выбирает новое семя каждый день, давая последовательный порядок в течение дня (позволяя легкие возможности паузы/возобновления), но свежий взгляд на каждый плейлист каждый новый день.

Ответ 5

если вы хотите получить, например. var count = 16 случайные строки из таблицы, вы можете написать

var rows = Table.OrderBy(t => Guid.NewGuid())
                        .Take(count);

здесь я использовал E.F, а таблица - Dbset

Ответ 6

Если целью получения случайных строк является выборка, я коротко говорил здесь о хорошем подходе от Larson и др., Microsoft Research где они разработали структуру выборки для Sql Server, используя материализованные представления. Существует также ссылка на фактическую бумагу.

Ответ 7

Пришел сюда интересно, как получить несколько случайных страниц из небольшого числа из них, поэтому каждый пользователь получает несколько разных случайных 3-х страниц.

Это мое окончательное решение, работающее с LINQ с запросом на список страниц в Sharepoint 2010. Это в Visual Basic, извините: p

Dim Aleatorio As New Random()

Dim Paginas = From a As SPListItem In Sitio.RootWeb.Lists("Páginas") Order By Aleatorio.Next Take 3

Вероятно, нужно получить некоторое профилирование перед запросом большого количества результатов, но оно идеально подходит для моей цели

Ответ 8

List<string> lst = new List<string>();
lst.Add("Apple"); 
lst.Add("Guva");
lst.Add("Graps"); 
lst.Add("PineApple");
lst.Add("Orange"); 
lst.Add("Mango");

var customers = lst.OrderBy(c => Guid.NewGuid()).FirstOrDefault();

Объяснение: Вставив guid (который является случайным), порядок с orderby будет случайным.

Ответ 9

У меня есть случайный запрос функции с DataTable s:

var result = (from result in dt.AsEnumerable()
              order by Guid.NewGuid()
              select result).Take(3); 

Ответ 10

Использование LINQ to SQL в LINQPad в качестве операторов С# выглядит как

IEnumerable<Customer> customers = this.ExecuteQuery<Customer>(@"SELECT top 10 * from [Customers] order by newid()");
customers.Dump();

Сгенерированный SQL

SELECT top 10 * from [Customers] order by newid()

Ответ 11

В приведенном ниже примере вызывается источник для извлечения счетчика, а затем применяется выражение пропусков на источнике с числом от 0 до n. Второй метод будет применять порядок, используя случайный объект (который будет заказывать все в памяти) и выберите номер, переданный в вызов метода.

public static class IEnumerable
{
    static Random rng = new Random((int)DateTime.Now.Ticks);

    public static T RandomElement<T>(this IEnumerable<T> source)
    {
        T current = default(T);
        int c = source.Count();
        int r = rng.Next(c);
        current = source.Skip(r).First();
        return current;
    }

    public static IEnumerable<T> RandomElements<T>(this IEnumerable<T> source, int number)
    {
        return source.OrderBy(r => rng.Next()).Take(number);
    }
}

Ответ 12

Я использую этот метод для получения случайных новостей и их работы отлично;)

    public string LoadRandomNews(int maxNews)
    {
        string temp = "";

        using (var db = new DataClassesDataContext())
        {
            var newsCount = (from p in db.Tbl_DynamicContents
                             where p.TimeFoPublish.Value.Date <= DateTime.Now
                             select p).Count();
            int i;
            if (newsCount < maxNews)
                i = newsCount;
            else i = maxNews;
            var r = new Random();
            var lastNumber = new List<int>();
            for (; i > 0; i--)
            {
                int currentNumber = r.Next(0, newsCount);
                if (!lastNumber.Contains(currentNumber))
                { lastNumber.Add(currentNumber); }
                else
                {
                    while (true)
                    {
                        currentNumber = r.Next(0, newsCount);
                        if (!lastNumber.Contains(currentNumber))
                        {
                            lastNumber.Add(currentNumber);
                            break;
                        }
                    }
                }
                if (currentNumber == newsCount)
                    currentNumber--;
                var news = (from p in db.Tbl_DynamicContents
                            orderby p.ID descending
                            where p.TimeFoPublish.Value.Date <= DateTime.Now
                            select p).Skip(currentNumber).Take(1).Single();
                temp +=
                    string.Format("<div class=\"divRandomNews\"><img src=\"files/1364193007_news.png\" class=\"randomNewsImg\" />" +
                                  "<a class=\"randomNews\" href=\"News.aspx?id={0}\" target=\"_blank\">{1}</a></div>",
                                  news.ID, news.Title);
            }
        }
        return temp;
    }

Ответ 13

Если вы используете LINQPad, перейдите в режим С# program и выполните следующие действия:

void Main()
{
    YourTable.OrderBy(v => Random()).FirstOrDefault.Dump();
}

[Function(Name = "NEWID", IsComposable = true)]
public Guid Random()
{
    throw new NotImplementedException();
}

Ответ 14

var cust = (from c in ctx.CUSTOMERs.ToList() select c).OrderBy(x => x.Guid.NewGuid()).Taket(2);

Выберите случайную 2 строку

Ответ 15

Чтобы добавить решение Marc Gravell. Если вы не работаете с самим классом datacontext (потому что вы каким-то образом проксируете его для подделки datacontext для целей тестирования), вы не можете использовать определенный UDF напрямую: он не будет скомпилирован SQL, потому что вы не используете его в подкласс или частичный класс вашего реального контекстного класса данных.

Обходной путь для этой проблемы - создать функцию Randomize в вашем прокси-сервере, подав ее с запросом, который вы хотите рандомизировать:

public class DataContextProxy : IDataContext
{
    private readonly DataContext _context;

    public DataContextProxy(DataContext context)
    {
        _context = context;
    }

    // Snipped irrelevant code

    public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
    {
        return query.OrderBy(x => _context.Random());
    }
}

Вот как вы можете использовать его в своем коде:

var query = _dc.Repository<SomeEntity>();
query = _dc.Randomize(query);

Чтобы быть полным, это как реализовать это в файле данных FAKE (который используется в объектах памяти):

public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
{
    return query.OrderBy(x => Guid.NewGuid());
}