12

I would like to translate the following SQL into LINQ:

SELECT
    (Select count(BidID)) as TotalBidNum,
    (Select sum(Amount)) as TotalBidVal
FROM Bids

I've tried this:

from b in _dataContext.Bids
select new { TotalBidVal = b.Sum(p => p.Amount), TotalBidNum = b.Count(p => p.BidId) }

but get an error "Bids does not contain a definition for "Sum" and no extension method "Sum" accepting a first argument of type "Bids" could be found.

How can I do this in LINQ?

Thanks

CONCLUDING:

The final answer was:

var ctx = _dataContext.Bids;

var itemsBid = (from b in _dataContext.Bids
               select new { TotalBidVal = ctx.Sum(p => p.Amount), TotalBidNum = ctx.Count() }).First();

4 Answers 4

26

You can write this query using GroupBy. The Lambda expression is as follows:

    var itemsBid = db.Bids
                     .GroupBy( i => 1)
                     .Select( g => new
                     {
                          TotalBidVal = g.Sum(item => item.Amount), 
                          TotalBidNum = g.Count(item => item.BidId)
                     });
Sign up to request clarification or add additional context in comments.

4 Comments

This is simple but does the trick. By the way, I'd like to know the purpose of operator ".GroupBy( i => 1)". Why do we need that?
How do we know that the aggregate functions (Sum, Count) are calculated in one iteration? Could it not be iterating the group twice for this? (which is something I want to avoid)
@Thomas.Benz that expression groups the iterable by a constant, so that all elements of the iterable end up in a single group. Normally with GroupBy you provide a function so that the items are put into multiple different groups
This is still using two iterations of the group g. It's just avoiding multiple iterations of the source items.
6

You could try this out. The variable b is an entity (for every iteration) while ctx is an entityset which has the extension methods you need.

var ctx = _dataContext.Bids;

var result = ctx
    .Select( x => new
    {
        TotalBidVal = ctx.Sum  ( p => p.Amount ),
        TotalBidNum = ctx.Count( p => p.BidId  )
    } )
    .First();

5 Comments

That did solve the error (although it seems like an unnecessary step - why is it needed?). There was a problem with my Count(p=> p.BidID) - an error that p.BidID wasn't boolean. I replaced it with Count() and now the query returns the correct sum and count but not as a single row. The same row over and over - I presume as many times as there are rows in the Bids table. How can I return a single row like in my original SQL query?
@BKahuna your query says "from b in _dataContext.Bids" thats an iteration. and you won't get one result even though u are trying to compute just the sum and count. You can end the lambda expression by calling First(). which will give u only one result like i've done.
@BKahuna please scroll my answer to the end and see the last call i make. i call the First() method which will ensure that i get only one row back (the sql generated is Top(1) )
When I do this I get a very inefficient CROSS JOIN SQL query. I need to use the GroupBy( x => 1 ) trick to get an efficient query.
This is ridiculous as an answer.
0

here's an alternative to scartag's solution:

(from b in _dataContext.Bids.Take(1)
select new 
{
    TotalBidVal = _dataContext.Bids.Sum(p => p.Amount), 
    TotalBidNum = _dataContext.Bids.Count()
}).Single();

Although there's no real reason you can't just say:

var result = new 
{
    TotalBidVal = _dataContext.Bids.Sum(p => p.Amount), 
    TotalBidNum = _dataContext.Bids.Count()
};

It hits the database twice, but its very readable

Comments

0

You could do it using the Aggregate Clause.

Aggregate t In _dataContext.Bids
Into TotalBidNum = Count(BidID),
     TotalBidVal = Sum(Amount)

If you're using Fx4+ or an extension dll for Fx2, you could also benfit from parallelism by using

Aggregate t In _dataContext.Bids.AsParallel

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.