Linq에서 Sql까지 임의의 행
조건이있을 때 Linq to SQL을 사용하여 임의의 행을 검색하는 가장 좋은 방법은 무엇입니까?
가짜 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-Server 제공에서 무작위 순서를 수행합니다 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
Entity Framework의 다른 샘플 :
var customers = db.Customers
.Where(c => c.IsActive)
.OrderBy(c => Guid.NewGuid())
.FirstOrDefault();
LINQ to SQL에서는 작동하지 않습니다. 는 OrderBy
단순히 떨어졌다되고있다.
편집 : 나는 이것이 단지 LINQ to SQLs가 아니라 LINQ to SQLs라는 것을 알았습니다. Marc의 코드를 사용하여 데이터베이스에서이를 수행하십시오. 이 답변을 LINQ to Objects의 잠재적 관심 지점으로 여기에 남겨 두었습니다.
이상하게도 실제로 카운트를 할 필요는 없습니다. 그러나 개수를 얻지 않으면 모든 요소를 가져와야합니다.
당신이 할 수있는 것은 "현재"값과 현재 카운트를 유지하는 것입니다. 다음 값을 가져올 때 임의의 숫자를 사용하고 "현재"를 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;
}
효율적으로 달성하는 한 가지 방법 Shuffle
은 임의의 int로 채워진 데이터에 열을 추가하는 것입니다 (각 레코드가 생성 될 때).
무작위 순서로 테이블에 액세스하는 부분 쿼리는 ...
Random random = new Random();
int seed = random.Next();
result = result.OrderBy(s => (~(s.Shuffle & seed)) & (s.Shuffle | seed)); // ^ seed);
이것은 데이터베이스에서 XOR 조작을 수행하고 해당 XOR의 결과에 따라 정렬됩니다.
장점 :-
- 효율적 : SQL이 순서를 처리하므로 전체 테이블을 가져올 필요가 없습니다.
- 반복 가능 : (테스트에 적합)-동일한 랜덤 시드를 사용하여 동일한 랜덤 순서를 생성 할 수 있습니다
이것은 내 홈 오토메이션 시스템이 재생 목록을 무작위 화하기 위해 사용하는 방법입니다. 매일 새로운 시드를 선택하여 하루 동안 일관된 순서를 유지하고 (쉬운 일시 중지 / 재개 기능 허용) 매일 각 재생 목록을 새롭게 살펴 봅니다.
예를 들어 var count = 16
테이블에서 임의의 행 을 얻으려면 쓸 수 있습니다.
var rows = Table.OrderBy(t => Guid.NewGuid())
.Take(count);
여기서는 EF를 사용했고 테이블은 Dbset입니다.
If the purpose of getting random rows is sampling, I have talked very briefly here about a nice approach from Larson et al., Microsoft Research team where they have developed a sampling framework for Sql Server using materialized views. There is a link to the actual paper also.
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();
Explanation: By inserting the guid (which is random) the order with orderby would be random.
Came here wondering how to get a few random pages from a small number of them, so each user gets some different random 3 pages.
This is my final solution, working querying with LINQ against a list of pages in Sharepoint 2010. It's in Visual Basic, sorry :p
Dim Aleatorio As New Random()
Dim Paginas = From a As SPListItem In Sitio.RootWeb.Lists("Páginas") Order By Aleatorio.Next Take 3
Probably should get some profiling before querying a great number of results, but it's perfect for my purpose
I have random function query against DataTable
s:
var result = (from result in dt.AsEnumerable()
order by Guid.NewGuid()
select result).Take(3);
The example below will call the source to retrieve a count and then apply a skip expression on the source with a number between 0 and n. The second method will apply order by using the random object (which will order everything in memory) and select the number passed into the method call.
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);
}
}
i use this method for take random news and its work fine ;)
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;
}
Using LINQ to SQL in LINQPad as C# statements look like
IEnumerable<Customer> customers = this.ExecuteQuery<Customer>(@"SELECT top 10 * from [Customers] order by newid()");
customers.Dump();
The generated SQL is
SELECT top 10 * from [Customers] order by newid()
If you use LINQPad, switch to C# program mode and do this way:
void Main()
{
YourTable.OrderBy(v => Random()).FirstOrDefault.Dump();
}
[Function(Name = "NEWID", IsComposable = true)]
public Guid Random()
{
throw new NotImplementedException();
}
var cust = (from c in ctx.CUSTOMERs.ToList() select c).OrderBy(x => x.Guid.NewGuid()).Taket(2);
Select random 2 row
To add to Marc Gravell's solution. If you are not working with the datacontext class itself (because you proxy it somehow e.g. to fake the datacontext for testing purposes), you cannot use the defined UDF directly: it will not be compiled to SQL because you're not using it in a subclass or partial class of your real data context class.
A workaround for this problem is to create a Randomize function in your proxy, feeding it with the query you want to be randomized:
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());
}
}
Here is how you'd use it in your code:
var query = _dc.Repository<SomeEntity>();
query = _dc.Randomize(query);
To be complete, this is how to implement this in the FAKE datacontext (which uses in memory entities):
public IOrderedQueryable<T> Randomize<T>(IQueryable<T> query)
{
return query.OrderBy(x => Guid.NewGuid());
}
참고URL : https://stackoverflow.com/questions/648196/random-row-from-linq-to-sql
'IT story' 카테고리의 다른 글
Java 클래스를 실행하기위한 Gradle (build.gradle을 수정하지 않고) (0) | 2020.07.30 |
---|---|
asyncio에서 요청을 어떻게 사용할 수 있습니까? (0) | 2020.07.30 |
PEM을 PPK 파일 형식으로 변환 (0) | 2020.07.30 |
다른 폴더에서 git“log”명령 사용 (0) | 2020.07.30 |
Sass의 이미지 경로에 변수가 있습니까? (0) | 2020.07.30 |