Explain COUNT query with ActiveRecord - mysql

I want to do something like the following:
Post.count.explain # doesn't work
This fails because EXPLAIN is a method on Relation and Post.count isn't a relation. It's just a regular integer that is the result of the query. So how could a count query be EXPLAINed?

Here's a form that generates the exact same SQL query, but returns a Relation to call explain on:
Post.select('count(*)').explain
Both generate the SQL
SELECT COUNT(*) FROM `posts`
...so the query plan should be the same.

From ActiveRecord::Relation#explain, we can make that method accept a block.
module ExplainBlock
def explain_block(&block)
exec_explain(collecting_queries_for_explain { instance_exec(&block) })
end
end
ActiveRecord::Relation.include(ExplainBlock)
Then Post.all.explain_block { count } .

The COUNT shouldn't affect the query plan, since the only difference it does is to tell the database to fetch the row data, but the rows need to be found anyway with/without the COUNT.

Related

How do i multiply 2 columns on each row and sum all the results using Sequelize?

I want to do something similar to:
SELECT SUM(columnA*columnB)
FROM someTable
WHERE randomCondition = true
If i do this raw query using Sequelize.query() method it works. Problem is that i have been having another issue with SQLite and because of that i must avoid using raw queries.
When i do Model.sum('columnA*columnB') i get a syntax error. How is this supposed to be done using Sequelize?
How do i multiply 2 columns on each row and sum all the results using Sequelize?
As far as I know, the only way to do this is with Sequelize.literal. For example:
Sequelize.Model.findAll({
attributes: [[db.sequelize.literal('SUM(col_a * col_b)'), 'result']],
})

Access query amazing

When I do that on access, SELECT RMonturesImp.N°Fac
FROM RMonturesImp, Rpartielun
WHERE NOT (RMonturesImp.N°Fac IN (1,2,5))
GROUP BY RMonturesImp.N°Fac;
but when I do this
SELECT RMonturesImp.N°Fac
FROM RMonturesImp, Rpartielun
WHERE NOT (RMonturesImp.N°Fac IN Requête2)
GROUP BY RMonturesImp.N°Fac;
it doesn't work (it shows 1,2,5 indeed) although the result of Requête2 (which is a query) is also (1,2,5). I can't understand this!
Thanks in advance
It's quite easy. The IN (1,2,5)) must be explicit as SQL will not evaluate an expression not to say a function to obtain the values for IN.
So build your SQL in code creating the string, or pull the values from a (temp) table.
Try this:
SELECT RMonturesImp.N°Fac
FROM RMonturesImp, Rpartielun
WHERE RMonturesImp.N°Fac NOT IN (Select N°Fac From Requête2)
GROUP BY RMonturesImp.N°Fac;

Using results in one query to use in another query - Orace MySql

I want to be able to use the results of the first query and place into the second query, sorry if this doesn't make much sense, im new to all of this.
First Query
SELECT "NAME", "TYPE","CATEGORY" "Meters" FROM BBT_Locations
WHERE SQRT(Power((:myLocX-LOCX), 2) + Power((:MyLocY - LOCY),2)) < :Distance;
Second Query
Select Round((:Distance/20)*4)as "Meters";
Can you please elaborate more as in which field value of 1st query you would like to use in 2nd query ? There are JOIN query and Sub query concept in SQL which can be used. But we should know the field that we would like to use and get value for, based on that we can select the kind of query to write.

Eloquent count distinct returns wrong totals

i'm having an issue with how eloquent is formulation a query that i have no access to. When doing something like
$model->where('something')
->distinct()
->paginate();
eloquent runs a query to get the total count, and the query looks something like
select count(*) as aggregate from .....
The problem is that if you use distinct in the query, you want something like
select count(distinct id) as aggregate from .....
to get the correct total. Eloquent is not doing that though, thus returning wrong totals. The only way to get the distinct in count is to pass an argument through the query builder like so ->count('id') in which case it will add it. Problem is that this query is auto-generated and i have no control over it.
Is there a way to trick it into adding the distinct on the count query?
P.S Digging deep into the builders code we find an IF statement asking for a field on the count() method in order to add the distinct property to the count. Illuminate\Database\Query\Grammars\BaseGrammar#compileAggregate
if ($query->distinct && $column !== '*')
{
$column = 'distinct '.$column;
}
return 'select '.$aggregate['function'].'('.$column.') as aggregate';
P.S.1 I know that in SQL you could do a group by, but since i'm eager loading stuff it is not a good idea cause it will add a IN (number of id's found) to each of the other queries which slows things down significantly.
I faced the exact same problem and found two solutions:
The bad one:
$results = $model->groupBy('foo.id')->paginate();
It works but it will costs too much memory (and time) if you have a high number of rows (it was my case).
The better one:
$ids = $model->distinct()->pluck('foo.id');
$results = $query = $model->whereIn('foo.id', $ids)->paginate();
I tried this with 100k results, and had no problem at all.
This seems to be a wider problem, discussed here:
https://github.com/laravel/framework/issues/3191
https://github.com/laravel/framework/pull/4088
Untill the fixes are shipped with one of the next Laravel releases, you can always try using the raw expressions, like below (I didnt test it, but should work)
$stuff = $model->select(DB::raw('distinct id as did'))
->where('whatever','=','whateverelse')
->paginate();
Reference: http://laravel.com/docs/queries#raw-expressions
$model->where('something')->distinct()->count('id')->paginate();

func.max get unexpected result?

I've got a table (story_id, votes)
with data
[(1,3), (2,4)]
when I try to do a query...
session.query(table.c.story_id, func.max(table.c.votes)).first()
i'll get:
(1,4)
the result I expect is:
(2,4)
where is the misunderstanding?
You are not grouping by anything so the database can simply return any row with a query like this. If you would add a group_by=table.c.story_id than this would return the proper result.
Most databases would, because of this, block these queries by default since the returned result would be arbitrary. In PostgreSQL for example you would get an error that story_id is not part of an aggregate query and not in the group by clause so it wouldn't know what row to return.
Either way, try this: session.query(table.c.story_id, func.max(table.c.votes)).group_by(table.c.story_id).first()