Symfony/Doctrine: SUM and AVG score of players - sql

I have in my database the tab: PLAYERS and a tab: SCORES.
In tab SCORES i have these rows: ID - IDPLAYER - SCORE
For example:
ID IDPLAYER SCORE
---------------------
1 1 5
2 2 4
3 1 3
4 2 1
5 1 9
I want put in a template this:
For "player 1" there are 3 scores.
The count of the scores is "17" (9+3+5).
The avg of the score of the player is "5.6" (17totscores / 3countScores).
I have an entity with ORM, it' ok.
I have a controller with this function:
public function avgScoreAction($id) {
$queryScore = $this->getDoctrine()
->getRepository('AcmeBundle:tabScores');
$queryAvgScore = $queryScore->createQueryBuilder('g')
->select("avg(g.score)")
->where('g.idPlayer = :idPlayer')
->setParameter('idPlayer', $id)
->getQuery();
$avgScore = $queryAvgScore->getResult();
$result = ("Score average: ".$avgScore);
return new Response($result);
But I have an error:
"Notice: Array to string conversion in this line:"
$result = ("Score average: ".$avgScore);
If I write this:
$response = new Response();
$response->setContent(json_encode(array($avgScore)));
$response->headers->set('Content-Type', 'application/json');
return $response;
I get this:
[[{"1":"5.6667"}]]
which is the correct avg, but what is: [[{"1":" and "}]] ?????

what is: [[{"1":" and "}]] ?
1 is the index of avg(g.score) in your query. To better understand why, try an echo of $queryAvgScore->getDql() before getResult().
Let's get back to the general question :
the SQL is :
SELECT AVG(SCORE) as AVG, COUNT(SCORE) as COUNT, IDPLAYER as PLAYER FROM SCORES GROUP BY IDPLAYER
and now with query builder :
$queryAvgScore = $queryScore->createQueryBuilder('g')
->select("avg(g.score) as score_avg, count(g.score) as score_count")
->where('g.idPlayer = :idPlayer')
->groupBy('g.idPlayer')
->setParameter('idPlayer', $id)
->getQuery();
Notice that i have added aliases, this is better than using indexes.
Hope it helps.

Symfony 2.6 is easy with DQL
$dql = "SELECT SUM(e.amount) AS balance FROM Bank\Entities\Entry e " .
"WHERE e.account = ?1";
$balance = $em->createQuery($dql)
->setParameter(1, $myAccountId)
->getSingleScalarResult();
Info:
http://doctrine-orm.readthedocs.org/en/latest/cookbook/aggregate-fields.html?highlight=sum

Related

Add new column count in Laravel controller

I am trying to add a new column total_count that contains the count of all rows in sample for pagination.
Is there a way to select count(*) as total_count in $sample itself instead of $total_count = $sample->count()
$var1 = $request->xyz;
$var2 = $request->abc;
$take = $request->take;
$skip = $request->skip;
$sample = DB::table('table_name')
->where('column_name1', $var1)
->where('column_name2', $var2)
->offset($skip)->limit($take)
->get();
$total_count = $sample->count();
$encrypted = AESEncrypt($sample);
return json_encode($encrypted);
OR can I write something like this
$sample = DB::table('table_name')
->select('table_name.*', DB::raw('COUNT(column_name) as total_count'))
->where('column_name1', $var1)
->where('column_name2', $var2)
->offset($skip)->limit($take)
->get();
You directly call
->paginate(10)
at the end of your query like:
$sample = DB::table('table_name')
->where('column_name1', $var1)
->where('column_name2', $var2)
->paginate(10);
Laravel itself handles all count pages etc.
You can use below code for total count of your table. If you need special where case then you should it too.
ModelName::count();
Or you can use
DB::table('table_name')->count();
You can read more in here

multiple joins with the same table in eloquent

Is there some elegant way to write the following query in eloquent? I would like to avoid using the raw query:
results(id, data)
result_filters (id, result_id, filter_id, value)
SELECT * FROM results, result_filters as age, result_filters as followers
WHERE age.result_id = results.id
AND followers.result_id = results.id
AND age.filter_id = 2
AND age.value > 90
AND followers.filter_id = 6
AND followers.value < 10000
If you are using the laravel eloquent
your model relation could be like
model Result:
public function resultFilters()
{
return $this->hasMany('App\ResultFilter');
}
model ResultFilter:
public function result()
{
return $this->belongsTo('App\Result','result_id');
}
try the below code:
$result = Result::find(1);
$data = $result->resultFilter()
->whereIn('filter_id',[2,6])
->whereBetween('value',[90,10000])
->get();
What do you think? It's uses DB::raw but it works
$data = DB::table(DB::raw("results, result_filters as age, result_filters as followers "))
->select(DB::raw("* "))
->where('age.result_id', 'results.id')
->where('followers.result_id', 'results.id')
->where('age.filter_id', 2)
->where('age.value', '<', 90)
->where('followers.filter_id',6)
->where('followers.value','<',10000)
->get();

Need help in converting SQL query to LINQ

I am new to the world of LINQ and hence I am stuck at converting one sql query to LINQ.
My SQL query is:
select COUNT(DISTINCT PAYER) as count,
PPD_COL FROM BL_REV
where BL_NO_UID = 1084
GROUP BY PPD_COL
The desired output is:
Count PPD_COL
12 P
20 C
I have written something like below in LINQ:
var PayerCount = from a in LstBlRev where a.DelFlg == "N"
group a by new { a.PpdCol} into grouping
select new
{
Count = grouping.First().PayerCustCode.Distinct().Count(),
PPdCol = (grouping.Key.PpdCol == "P") ? "Prepaid" : "Collect"
};
But it is not giving me the desired output. The count is returned same for PPD_COL value P & C. What am I missing here?
Change the groupby as following. in the group group only the property you need and then in thr by no need to create an anonymous object - just the one property you are grouping by.
var PayerCount = from a in LstBlRev
where a.DelFlg == "N"
group a.PayerCustCode by a.PpdCol into grouping
select new
{
Count = grouping.Distinct().Count(),
PPdCol = grouping.Key == "P" ? "Prepaid" : "Collect"
};

Linq query using list output as input

I am using Linqpad and have odata connection setup.
I have a query as follows
QUERY1
void Main()
{var a = from cpuid in Computers
where cpuid.DnsHostName == "xyz"
select new {
ID = cpuid.TechnicalProductsHosted.Select (x => new { Id = x.Id }),
System_Dept = cpuid.SystemDepartment,
};
Console.WriteLine(a);
}
The output : it returns 4 ids but one department which is common among all four id's. When i query otherway round i.e
QUERY2
var a = from id in TechnicalProducts
where id.Id == "ID-15784"
select new
{System_Dept = id.Computers.Select(x => x.SystemDepartment),
Support_Team = id.Computers.Select(x => x.SupportTeam)
};
Console.WriteLine(a);
The output : 4 departments for the id. I wish to have the whole list of departments in the first case. How is it possible? In query 1 Can i take id as input for System Department and query it somehow?
the output samples

Why isn't this LINQ Group By aggregating the rows in vb.net?

I have a table that has a 2 part key; an ID column, and a version number. I'm trying to select 'only the latest version' of the records.
I'm trying to use the expression style of LINQ, to achieve a GROUP BY, and pull out the aggregate MAX value of the Version. However no aggregation is taking place.
Summarized Code:
From C In Credentials
Group Join ....
Group Join ....
Group C.CredentialID, NE.ClientID, C.Version By
NE.ClientID, C.CredentialID Into CGroup = Group
From CG In CGroup
Select New With {
.ClientID = CG.ClientID,
.CredentialID = CG.CredentialID,
.MaxVersion = CGroup.Max(Function(p) p.Version)
}
Actual Results:
ClientID CredentialID MaxVersion
1196 1 3
1196 1 3
1196 1 3
1196 2 1
Desired Results:
ClientID CredentialID MaxVersion
1196 1 3
1196 2 1
Also tried, same results:
Group C By Key = New With
{Key NE.ClientID, Key C.CredentialID} Into CGroup = Group
From CG In CGroup
Select New With {
.ClientID = Key.ClientID,
.CredentialID = Key.CredentialID,
.MaxVersion = CGroup.Max(Function(p) p.Version)
}
I'm looking for a solution that does not involves creating custom classes with matching properties and custom sorting / grouping functions, and does not use the lambda expressions on the tail end of the query.
Thanks!
From CG In CGroup
This line calls Queryable.SelectMany and unpacks the groups. Don't unpack your groups!
Remove that line and end with:
Select New With {
.ClientID = CGroup.Key.ClientID,
.CredentialID = CGroup.Key.CredentialID,
.MaxVersion = CGroup.Max(Function(p) p.Version)
}
The problem is that the anonymous class defined for the key does not evaluate equality in the way you like. Instead, you can use a Tuple for the key:
From C In Credentials
...
Group C.CredentialID, NE.ClientID, C.Version By key =
New Tuple(Of Integer, Integer)(NE.ClientID, C.CredentialID)
Into CGroup = Group
Select New With {
.ClientID = key.Item1,
.CredentialID = key.Item2,
.MaxVersion = CGroup.Max(Function(p) p.Version)
}