Why is count(id) resulting 3 dimensional array? - mysql

Im using this direct query method in cakephp to get a count (against the norms of MVC).
$count = $this->History->query("SELECT count(id) AS x FROM ratings WHERE id='3' AND employee='28'");
But it turns out that, i need to use $count[0][0]['x'] to get the value.
Why isnt it available at $count['x']?

in your case it will return it in a general way: 0 = iterate over all models, and again 0 since you dont have a specific model name). your result will always be in $count[0][0]['fieldname'] then.
it is highly recommended to always use the wrapper methods if possible.
why are you not using the cakephp database wrapper methods as documented?
$count = $this->History->find('count', array('conditions'=>array('id'=>3, 'employee'=>28));
?
it would result in the expected output x

Simply, its because the function
$this->History->query(....);
does not return a single dimensional array. I will suggest you to create a helper function, which extracts the single dimensional array and return it.
function single_query($query) {
$result = $this->History->query($query);
return $result[0][0];
}
then use it
$count = $this->single_query("SELECT count(id) AS x FROM ratings WHERE id='3' AND employee='28'");

Related

Query Builder appending a limit by itself

I have a "big" query with 10 joins, and finally a single where condition.
I also have about 6 arrays, each being filled with a select statement from said query.
$first_array = $query->select()->first();
In two of the arrays, I get the data using get() instead of first(). The issue is, the get() method is only returning one row, when I know for a fact that there are two that match the condition. I used the toSql() method to see the resulting query, only to find there is a limit 1 being appended to the query that I did not place. Is the limit being appended because I'm using first() in some of the queries, which is limiting my results to one row? I've tried executing the query in my database manager and after removing the limit 1 from the query it does return the two rows I'm expecting.
The issue was, if you did this like I did:
$array1 = $query->select()->first();
$array2 = $query->select()->first();
$array3 = $query->select()->first();
$array4 = $query->select()->first();
$array5 = $query->select()->get();
The first() method calls set the limit 1, and using get() afterwards does not remove the limit.
If you use get() first then first() like so:
$array5 = $query->select()->get();
$array1 = $query->select()->first();
$array2 = $query->select()->first();
$array3 = $query->select()->first();
$array4 = $query->select()->first();
then the issue does not occur.
Replace first() with get() is the answer. first() is for retrieving a single model: https://laravel.com/docs/8.x/eloquent#retrieving-single-models where get() returns you the collection of results: https://laravel.com/docs/8.x/eloquent#collections

Laravel 5.4 formatting result set

Can someone help me convert this query so that my result set is in different format?
$sessions = new Session();
$results = $sessions->where('session_status', $status)->where('application_period_id', (int) ApplicationPeriod::all()->last()->id)->get()->pluck('speaker_id');
$speakers = Speaker::whereIn('id', $results)
->with('session.audiancesession.audiances')
->with('session.subjectsession.subjects')
->with(['session' =>
function ($query) use($status) {
$query->where('session_status', '=', $status);
}])->orderBy('last_name')->get();
This is requested via Ajax(axios)... Now this is how result is formatted:
Obj->data(array of objects)->[0]->name
->address
->session(array of objects)
->[0]->time
->fee
My issue is that my session parameter is array and there can only ever be (1) so I don't need to to be an array and I would like to have object (json) instead.
Thank you!
You might have more success if you change your client-side code to work with an array of sessions each session having its speaker, that means your original query would be like
$sessions = Sessions::with([
'speaker', 'audiancesession.audiances', 'subjectsession.subjects'
])->where('application_period_id', (int) ApplicationPeriod::orderBy('id','DESC')->first())->get();
Note the order by -> first in the ApplicationPeriod makes it so you don't have to get all application periods from the database to memory.
Then your client side should handle an array of sessions.
You can transform the above slightly using to get a similar result to what you need:
$speakers = $sessions->map(function ($session) {
$speaker = collect($session->speaker->toArray());
$speaker->put('session', collect($session->toArray())->except('speaker'));
return $speaker;
})->orderBy('last_name','DESC');
Though I wouldn't guarantee the result here as I've not tested it on your (complex looking) data.

Return array of values instead of array of objects from SQL query in Rails

I have a SQL query in a Rails model that responds with an array of objects. And each object has an attribute called points with a value.
But its preferable for query to just return an array of points like [10,15,5] instead of [object,object,object] which requires then extracting the points out into another array to be useful.
Model file
LAST_3_SELECT = "
SELECT
(
(data.ap / (data.apa * 1.0))
+
(data.vp / (data.vpa * 1.0))
)
/ 2 * 1.5 * data.level
AS points
FROM data
WHERE data.user_id = ?
GROUP BY data.id
ORDER BY data.created_at DESC
LIMIT 3
"
def self.last_3(user_id)
connection.select_all(sanitize_sql_array( [LAST_3_SELECT, user_id]), "last-3")
end
Is this possible to do in a query itself, or necessary to do in a method outside it?
I don't have much experience writing raw SQL queries into Rails methods so any guidance would be very appreciated.
You can use pluck to get the points into an array
def self.last_3(user_id)
connection.select_all(sanitize_sql_array( [LAST_3_SELECT, user_id]), "last-3").pluck(:points)
end
Here points is the column name to be plucked

Doctrine query returns extra field in result

I have a Doctrine query;
$q = Doctrine_Query::create()->select('s.monthly_volume')
->from('SearchVolume s')
->innerJoin('s.Keywords k')
->where('k.group_id = ?',array($group_id));
I just want it to return the monthly_volume value in the result array. It currently returns monthly_volume and id, I don't want it to return the id in result.
Doctrine automatically adds the primary key field to the results in almost every type of hydration mode.
In a case like this where you want a simple array and only have a single field being selected, the answer is the Single Scalar Hydration mode. Use it like this:
$q = Doctrine_Query::create()->select('s.monthly_volume')
->from('SearchVolume s')
->innerJoin('s.Keywords k')
->where('k.group_id = ?');
$monthly_volumes = $q->execute(array($group_id), Doctrine_Core::HYDRATE_SINGLE_SCALAR);
You should find that $monthly_volumes is a simple one-dimensional array containing only the value(s) you wanted.

Working around LinqToSQls "queries with local collections are not supported" exception

So, I'm trying to return a collection of People whose ID is contained within a locally created collection of ids ( IQueryable)
When I specify "locally created collection", I mean that the Ids collection hasnt come from a LinqToSql query and has been programatically created (based upon user input).
My query looks like this:
var qry = from p in DBContext.People
where Ids.Contains(p.ID)
select p.ID;
This causes the following exception...
"queries with local collections are not supported"
How can I find all the People with an id that is contained within my locally created Ids collection?
Is it possible using LinqToSql?
If Ids is a List, array or similar, L2S will translate into a contains.
If Ids is a IQueryable, just turn it into a list before using it in the query. E.g.:
List<int> listOfIDs = IDs.ToList();
var query =
from st in dc.SomeTable
where listOfIDs.Contains(st.ID)
select .....
I was struggling with this problem also. Solved my problem with using Any() instead
people.Where(x => ids.Any(id => id == x.ID))
As the guys mentioned above, converting the ids, which is of type IQueryable to List or Array will solve the issue, this will be translated to "IN" operator in SQL.But be careful because if the count of ids >= 2100 this will cause another issue which is "The server supports a maximum of 2100 parameters" and that is the maximum number of parameters(values) you can pass to "IN" in SQL server.
Another alternative would be keeping ids as IQueryable and using LINQ "Any" operator instead of "Contains", this will be translated to "EXISTS" in SQL server.
I'm sorry but the answers here didn't work for me as I'm doing dynamic types further along.
What I did was to use "UNION" in a loop which works great. Here's how:
var firstID = cityList.First().id;
var cities = dc.zs_Cities.Where(c => c.id == firstID);
foreach(var c in cityList)
{
var tempCity = c;
cities = cities.Union(dc.zs_Cities.Where(cty => cty.id == tempCity.id));
}