In my Laravel API everyone and everywhere written select *, even when it does not need to collect all the column data.
Is it better to use eloquent select instead, specifying exactly what's needed?
There are several ways of doing this:
To select only specific fields you can do something like:
ModelName::all('column1', 'column2', 'column3');
Or using get:
ModelName::get(['id', 'date']);
For Models with relationships:
$model->relation()->only(['column1', 'column2']);
If you need to eager load while selecting specific columns with relationship:
$data = Model::with(array('relation' => function($query)
{
$query->select('name');
}))->get();
You can read more at collections
Related
i am little bit confused that how my query convert in laravel..
select users.username,users.photo, questions.*,
(Select count(*) from answers
where answers.q_id=questions.id) as aAccount from questions
INNER JOIN users ON users.id=questions.user_id
Use Raw query
These expressions will be injected into the query as strings, so be careful not to create any SQL injection points! To create a raw expression, you may use the DB::raw method
DB::table('questions')
->join('users', 'users.id', '=', 'questions.user_id')
->select('users.username','users.photo', 'questions.*',
DB::raw("
( Select count(*) from answers
where answers.q_id=questions.id
)as 'aAccount'")
->get();
I upvoted JYoThl answer as it's exactly how I'd breakdown this query into eloquent, though in instances where a portion of your Eloquent query becomes raw, I personally prefer keeping the entire sql raw. You can still inject variables into it if required.
In my experience, the amount of time spent normalizing a more complex query like this will be used when you go back to the code to re-read it.
Here's how you would pass your sql in it's raw format. I also like to convert the array into a collection, as collections offer a variety of methods. Hope this helps!
$questions = collect(DB::select( DB::raw("
select users.username,users.photo, questions.*,
(Select count(*) from answers where answers.q_id=questions.id) as aAccount
from questions
INNER JOIN users ON users.id=questions.user_id")
));
You would add variables into an array() area if you want to inject a variable. If you wanted to do that you would do something like this:
DB::select( DB::raw("select * from user where user = :user"), array('user' => $user))
I have two tables Models and Cars related as per cars.model_id = model.id.
Car belongsTo Model and Model hasMany Cars.
When I would like to do a search based on the Model name in the cars table I do the following query:
Car::join('models', 'cars.model_id', '=', 'models.id)
->where('models.name', 'like', '%'.$term.'%')
->paginate($_ENV['ITEMS_PER_PAGE']);
My problem is that Eloquent ORM of Laravel in that case returns the model.id as the main id, so resultset will have the model.id as Id instead of the Car.id. Any solution for that?
As per the documentation of Laravel, I thought that Eloquent would assume correctly the table Id without any help:
Note: Eloquent will also assume that each table has a primary key
column named id. You may define a primaryKey property to override this
convention. Likewise, you may define a connection property to override
the name of the database connection that should be used when utilizing
the model.
Just don't SELECT id or none of the models fields if you don't need them (where clause will work anyway)
Car::join('models', 'cars.model_id', '=', 'models.id')
->where('models.name', 'like', '%'.$term.'%')
->paginate($_ENV['ITEMS_PER_PAGE'], ['cars.*','models.fieldsYouNeedOrNothing']);
side note: You can use whereHas() instead of join to do it more 'eloquent' way if you really don't need joined table's fields:
Car::whereHas('models', function ($query) use ($term) {
$query->where('models.name', 'like', '%'.$term.'%');
})->paginate($_ENV['ITEMS_PER_PAGE']);
This will run subquery on models table and leave you without any worries about the keys.
I'm new to Symfony2. It suggested to use doctrine so I'm learning it.
Now I am testing to fetch data from 2 tables. Suppose table names are tb_info & tb_group. I've 2 classes with same name with proper ORM that represents these 2 tables.
In simple query, we do
"SELECT * FROM tb_info,tb_group"
And all the magical data come to my hand. Now with Doctrine I can't find simple way like this. I tried
$query = $em->createQuery(
'SELECT p
FROM AcmeDbBundle:tb_info,AcmeDbBundle:tb_group p'
);
This doesn't work. I saw some ways to collect data from 2 different tables. But I don't want to use relationship.
Is there any simple ways to write query in doctrine to fetch data from multiple tables?? Am I missing anything?
You can use Doctrine QueryBuilder in a repository function:
$queryBuilder = $this->_em->createQueryBuilder();
$queryBuilder->addSelect("position,candidate")
->from("RadsphereRecruitmentBundle:Position", 'position')
->from("RadsphereRecruitmentBundle:Candidate", 'candidate')
->andWhere("position.open = :open")
->setParameter("open",true);
return $queryBuilder->getQuery()->getResult();
I fairly new to YII and still trying to understand it all. However from what I can tell when you do something like
yourModel->findAll(criteria)
Is like "Select * from"? or is it more like "Select yourModel->Attributes from"? In either case I was wondering in CDbCriteria is there a way to remove columns from the select. My case I have a user table that contains password I would like to prevent this from being added in the query.
Thanks,
Ofcourse you can select specific columns, just use the select property of CDbCriteria:
$criteria=new CDbCriteria();
$criteria->select='column1, column2';// or you can use array array('column1','column2')
$manymodels=$yourmodel->findAll($criteria);
So it is more like : "Select criteria->select from yourmodelclass' dbtable".
Note that findAll() will return you an array of models.
So, I need to search a real estate database for all homes belonging to realtors who are part of the same real estate agency as the current realtor. I'm currently doing this something like this:
$agency_data = $this->Realtor->find('all',array(
'conditions'=>
array(business_name'=>$realtor_settings['Realtor']['business_name']),
'fields'=>array('num'),
'recursive'=> -1
));
foreach($agency_data as $k=>$v){
foreach($v as $k=>$v1){
$agency_nums[] = $v1['num'];
}
}
$conditions = array(
'realtor_num'=>$agency_nums
);
It seems a bit crazy to me that I'm having to work so hard to break down the results of my first query, just to get a simple, one-dimensional array of ids that I can use to build a condition for my subsequent query. Am I doing this in an insanely roundabout way? Is there an easy way to write a single CakePHP query to communicate "select * from homes where realtor_num in (select num from realtors where business_name = 'n')"? If so, would it be any more efficient?
For sure it's complicated (in your way) :)
Depending from the results you can do following:
$agency_data = $this->Realtor->find('list',array(
'conditions'=>array('business_name'=>$realtor_settings['Realtor']['business_name']),
'fields'=>array('num', 'num'),
'recursive'=> -1
));
$agency_data; //this already contain array of id's
Method 2 - building a sub query there are 2 ways strict and not so strict :) The first one you can see here (search for Sub-queries).
The other option is to have following conditions parameter:
$this->Realtor->find('all', array('conditions'=>array('field in (select num from realtors where business_name like "'.$some_variable.'"))));
Of course be careful with the $some_variable in the sub-query. You shold escape it - use Sanitize class for example.
$agency_data = $this->Realtor->find('all',array(
'conditions'=>
array('business_name'=>$realtor_settings['Realtor']['business_name']),
'fields'=>array('num'),
'recursive'=> -1
));
$conditions = Set::extract("{n}.Realtor.num", $agency_data);
I would use something like Set::extract to grab the list of data you are looking for. The advantage of doing it this way is that you can reuse the same dataset in other places and save queries. You could also write the set::extract statement in this format:
$conditions = Set::extract("/Realtor/num", $agency_data);