Qual é a melhor (e mais rápida) maneira de recuperar uma linha aleatória usando Linq para SQL quando tenho uma condição, por exemplo, algum campo deve ser verdadeiro?
c#
.net
linq-to-sql
Julien Poulin
fonte
fonte
Respostas:
Você pode fazer isso no banco de dados, usando um UDF falso; em uma classe parcial, adicione um método ao contexto de dados:
Então apenas
order by ctx.Random()
; isso fará uma ordem aleatória no SQL-Server, cortesia deNEWID()
. ieObserve que isso só é adequado para tabelas de tamanho pequeno a médio; para tabelas grandes, isso terá um impacto no desempenho do servidor e será mais eficiente encontrar o número de linhas (
Count
) e, em seguida, escolher uma ao acaso (Skip/First
).para abordagem de contagem:
fonte
Outro exemplo para Entity Framework:
Isso não funciona com LINQ to SQL. O
OrderBy
está simplesmente sendo descartado.fonte
EDIT: Acabei de notar que este é LINQ to SQL, não LINQ to Objects. Use o código de Marc para que o banco de dados faça isso por você. Deixei esta resposta aqui como um ponto de interesse potencial para LINQ to Objects.
Estranhamente, você realmente não precisa fazer a contagem. No entanto, você precisa buscar todos os elementos, a menos que obtenha a contagem.
O que você pode fazer é manter a ideia de um valor "atual" e a contagem atual. Ao buscar o próximo valor, pegue um número aleatório e substitua o "atual" por "novo" com uma probabilidade de 1 / n, onde n é a contagem.
Portanto, quando você lê o primeiro valor, sempre o torna o valor "atual". Quando você lê o segundo valor, pode torná-lo o valor atual (probabilidade 1/2). Quando você lê o terceiro valor, pode torná-lo o valor atual (probabilidade 1/3) etc. Quando você fica sem dados, o valor atual é aleatório de todos os que você lê, com probabilidade uniforme.
Para aplicar isso com uma condição, simplesmente ignore qualquer coisa que não atenda à condição. A maneira mais fácil de fazer isso é considerar apenas a sequência de "correspondência" para começar, aplicando primeiro uma cláusula Where.
Aqui está uma implementação rápida. Eu acho que está tudo bem ...
fonte
current
irá sempre ser definido para o primeiro elemento. Na segunda iteração, há uma mudança de 50% que será definido para o segundo elemento. Na terceira iteração, há 33% de chance de ser definido para o terceiro elemento. Adicionar uma instrução break significaria que você sempre sairia após ler o primeiro elemento, tornando-o nem um pouco aleatório.Uma maneira de fazer isso com eficiência é adicionar uma coluna aos seus dados
Shuffle
que é preenchida com um int aleatório (conforme cada registro é criado).A consulta parcial para acessar a tabela em ordem aleatória é ...
Isso faz uma operação XOR no banco de dados e ordena pelos resultados desse XOR.
Vantagens: -
Esta é a abordagem usada pelo meu sistema de automação residencial para randomizar playlists. Ele pega uma nova semente a cada dia, dando uma ordem consistente durante o dia (permitindo recursos fáceis de pausar / retomar), mas uma nova visão de cada lista de reprodução a cada novo dia.
fonte
result = result.OrderBy(s => s.Shuffle ^ seed);
(ou seja, não há necessidade de implementar o XOR por meio dos operadores ~, & e |).se você quiser obter, por exemplo
var count = 16
linhas aleatórias da tabela, você pode escreveraqui eu usei EF, e a Tabela é um Dbset
fonte
Se o objetivo de obter linhas aleatórias é amostrar, falei brevemente aqui sobre uma boa abordagem de Larson et al., Equipe de pesquisa da Microsoft, onde desenvolveram uma estrutura de amostragem para Sql Server usando visualizações materializadas. Também existe um link para o artigo em si.
fonte
Explicação: Ao inserir o guid (que é aleatório), a ordem com orderby seria aleatória.
fonte
Vim aqui querendo saber como obter algumas páginas aleatórias de um pequeno número delas, de modo que cada usuário receba algumas 3 páginas aleatórias diferentes.
Esta é minha solução final, trabalhando em consultas com LINQ em uma lista de páginas no Sharepoint 2010. Está no Visual Basic, desculpe: p
Provavelmente deveria obter algum perfil antes de consultar um grande número de resultados, mas é perfeito para o meu propósito
fonte
Eu tenho uma consulta de função aleatória contra
DataTable
s:fonte
O exemplo abaixo chamará a fonte para recuperar uma contagem e, em seguida, aplicará uma expressão de salto na fonte com um número entre 0 e n. O segundo método aplicará a ordem usando o objeto aleatório (que ordenará tudo na memória) e selecionará o número passado na chamada do método.
fonte
eu uso este método para obter notícias aleatórias e seu funcionamento;
fonte
Usando LINQ to SQL no LINQPad como instruções C # parecem
O SQL gerado é
fonte
Se você usa LINQPad , alterne para o modo de programa C # e faça o seguinte:
fonte
Selecione 2 linhas aleatórias
fonte
Para adicionar à solução de Marc Gravell. Se você não estiver trabalhando com a classe do datacontext em si (porque você o faz proxy de alguma forma, por exemplo, para falsificar o datacontext para fins de teste), você não pode usar o UDF definido diretamente: ele não será compilado para SQL porque você não o está usando em um subclasse ou classe parcial de sua classe de contexto de dados reais.
Uma solução alternativa para esse problema é criar uma função Randomize em seu proxy, alimentando-o com a consulta que você deseja que seja randomizada:
Aqui está como você o usaria em seu código:
Para ser completo, esta é a forma de implementar isso no datacontext FAKE (que usa em entidades de memória):
fonte