I'm trying to find all rows with none or less than 3 relations. What would be the best approach for that?
I tried the following code with several different selects, having, joins but I can't figure out how to do it the right way:
$db = $this->createQueryBuilder('u');
$db->addSelect('COALESCE(COUNT(errors), 0) AS HIDDEN errorCount');
$db->join('u.errors', 'errors');
$db->where('u.field1 IS NULL AND u.field2 NOT LIKE \'\'');
$db->having('errorCount < 3');
Thank you very much in advance.
The COUNT function is an aggregate function which will return a single result unless you instruct it to group by something.
$db = $this->createQueryBuilder('u');
$db->addSelect('COUNT(errors) AS HIDDEN errorCount');
$db->leftJoin('u.errors', 'errors');
$db->where('u.field1 IS NULL AND u.field2 NOT LIKE \'\'');
$db->having('errorCount < 3');
$db->groupBy('u');
Additionally, if you want to count the number of relations that may or may not exist use a LEFT JOIN. The count on these results will be 0 which is < 3.
Related
To show related Articles on a website, I need the Cast() function.
My Query looks like:
SELECT
*,
(CAST(a.uploader = ?1 AS UNSIGNED)
+ CAST(a.param2 = ?2 AS UNSIGNED)
...
) AS matches_count
FROM articles AS a
ORDER BY matches_count DESC
It counts the matches and sorts by the highest number of matches_counts.
The problem is, that there's no Cast() function built into doctrine.
After hours of trial and error I found an already available custom DQL Function:
https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/Cast.php
I registered it inside my doctrine.yml.
But it doesn't work, because it expects Cast(X AS Y) and not Cast(Y $comparisonOperator X).
When I'am using this inside my repository, by example:
$this->createQueryBuilder('a, (CAST(author=25 AS UNSIGNED) AS matches_count)')
->getQuery()
->getResult()
;
I get this error, because it doesn't expect a comparison operator:
[Syntax Error] line 0, col 29: Error: Expected Doctrine\ORM\Query\Lexer::T_AS, got '='
Do you know how to maybe extend that class for and not Cast(Y $comparisonOperator X) instead of Cast(X AS Y)?
I didn't find any solution on the internet and tried it for hours.
Thank you in advance for taking the time to write an answer!
Update:
I changed line 37 in the above mentioned custom DQL class for Cast:
//old
//$this->fieldIdentifierExpression = $parser->SimpleArithmeticExpression();
//new
$this->fieldIdentifierExpression = $parser->ComparisonExpression();
and how to create the query:
$this->createQueryBuilder('a')
->select('a, (CAST(a.averageRating=:averageRating AS UNSIGNED) + CAST(a.author=:author AS UNSIGNED)) AS matches_count')
->setParameter('averageRating', $averageRating)
->setParameter('author', $author)
->orderBy('matches_count', 'DESC')
->getQuery()
->getResult();
and that seems to be it!
I hope its the right way of doing it, will help someone and that is the best way for this purpose.
To improve performance later, I plan to cache 10 ids of recommended articles for every single article page into its own table.
So it doesn't need to do the calculation on page load.
This table could get recreated every 24h via a cronjob.
ID | recommended_article_ids | article_id
1 | 10,24,76,88| 5
Feedback and tips are much appreciated!
I'm learning LINQ, and I'm trying to figure out how to get all members with the last order failed (each member can have many orders). For efficiency reasons I'd like to do it all in LINQ before putting it into a list, if possible.
So far I believe this is the right way to get all the members with a failed order which joined recently (cutoffDate is current date -10 days).
var failedOrders =
from m in context.Members
from o in context.Orders
where m.DateJoined > cutoffDate
where o.Status == Failed
select m;
I expect I need to use Last or LastOrDefault, or possibly I need to use
orderby o.OrderNumber descending
and then get the First or FirstOrDefault as suggested in this stackoverflow answer.
Note that I want to look at ONLY the last order for a given member and see if that has failed (NOT just find last failed order).
Normally you would write something like:
var failedOrders = from m in context.Members
where m.DateJoined > cutoffDate
select new
{
Member = m,
LastOrder = m.Orders.OrderByDescending(x => x.OrderNumber).FirstOrDefault()
} into mlo
// no need for null checks here, because the query is done db-side
where mlo.LastOrder.Status == Failed
select mlo; // or select mlo.Member to have only the member
This if there is a Members.Orders relationship
Rows are selected like that:
$book->getBookGenreToBooks()->???()
I want to change the column «checked» of all selected rows.
Your given solution in your answer is very inefficient since it creates for each update a new query. A better way is to do all changes in one query:
BookGenreQuery::create()
->filterByBookId($book->getId())
->update(array('Checked' => 1));
I don't know how exactly your relations and fields are named by you should get the idea behind it.
$genresToBook = $book->getBookGenreToBooks();
foreach ($genresToBook as $genreToBook) {
$genreToBook->setChecked(1); //Set any data here
}
$genresToBook->save();
This isn't exactly what I want, but that works fine to me.
I am looking for a function which will list out the content types which a specific term (tid) can be applied to.
There doesn't seem to be a direct way to do it from http://api.drupal.org/api/search/6/taxonomy.
Any ideas?
No, there doesn't seem to be one. You should be able to use this query, though.
$c = db_query(db_rewrite_sql("SELECT v.* FROM {vocabulary} v INNER JOIN {vocabulary_node_types} n ON v.vid = n.vid WHERE n.type = '%s' ORDER BY v.weight, v.name", 'v', 'vid'), $node->type);
Source: http://api.drupal.org/api/drupal/modules--taxonomy--taxonomy.module/function/taxonomy_form_alter/6
Or a simplified version of that, if you for example only need the vid.
I want to compare rows of two grid views.GW1 and GW2.
When I click a Search Button ,I want to check the Values in the GW2,and if GW1 and GW2 have same PayID ,EmpID,then that specific row of GW1 must be disabled
Thanks
int i = 0;
while(i < GridView1.Rows.Count && i < GridView2.Rows.Count)
{
if(
GridView1.Rows[i].Cells[column for pay ID].Text == GridView2.Rows[i].Cells[column for pay ID].Text &&
GridView1.Rows[i].Cells[column for emp ID].Text == GridView2.Rows[i].Cells[column for emp ID].Text))
{
GridView1.Rows[i].Enabled = false;
}
i++;
}
Only way I can think of is to loop through table one and search for similar rows in table two. This is how you can do this:
Loop through the Table 1.
Use DataTable.Select to find if there are rows with same PayID and EmpID in Table 2.
If the method returns more than 0 rows, then disable the rows.
Apart from this, you can also think about writing/searching a method which can give you intersection of two tables. If these two columns are priamry keys, then this will work. If not, then you will need to tweak the code as per your need.
do something like this, its not the actual code, but you will have the idea.
for i=0 to gw1rowscount-1
for j=0 to gw2rowscount-1
if gw1(i)(column1)=gw2(j)(column1) and gw1(i)(column2)=gw2(j)(column2) then
end if
next
next