Alias for table - yii2

I have two tables. The first - Product, the second - Category. They contain fields with the same name - 'name'.
In model Product I added following code:
public function getCategory(){
return $this->hasOne(Category::className(), ['id' => 'cat_id']);
}
I need to show in GridView the column from table Category. I added following code for this in the model ProductSearch:
$query->joinWith(['category' => function($query) { $query->from(['cat' => 'category']); }]);
This code adds the alias cat for the table Category.
After that I got an error:
SQLSTATE[23000]: Integrity constraint violation: 1052 Column 'name' in where clause is ambiguous
The SQL being executed was: SELECT COUNT(*) FROM `product` LEFT JOIN `category` `cat` ON `product`.`cat_id` = `cat`.`id` WHERE `name` LIKE '%aasdadadsdgdgdg%'
Error Info: Array
(
[0] => 23000
[1] => 1052
[2] => Column 'name' in where clause is ambiguous
)
How can I add the alias for the table Product?

Open your ProductSearch model, navigate to the search($params) method. Below you should see the filtration part:
$query->andFilterWhere(['like', 'name', $this->name])
fix the ambigous part by writing table name product to that line.
$query->andFilterWhere(['like', 'product.name', $this->name])
or..
$query->andFilterWhere(['like', self::tableName() . '.name', $this->name])
This'll giving precise info that name should be queried from product.name table.
The interesting part is that you don't get the error until you join the Category table.
Imho, it's the worst to find this errors as it seems like everything is working, until search functionality is used.

Related

CakePHP 3 join on a secondary key using ORM

CakePHP 3.5.13 - working with a legacy database. I have a table called substances where the primary key is id. There is also another column in this table called app_id.
The majority of tables in the application have a foreign key which means they can be joined to substances.id. There is one table called article_95 which has a field article_95.app_id and therefore the join must be made to substances.app_id (not substances.id - there is no reference to that field inside the article_95 table at all).
The application performs a search based on up to 11 inputs. I'm using the ORM to dynamically build the query object before executing it.
I begin my query like this:
$query = $Substances->find()->select(['id' => 'Substances.id'])->distinct();
Then if I wanted to do something where the join maps to substances.id, I'm doing it like this:
// Search by CAS Number
if ($this->request->getData('cas_number')) {
$cas_number = $this->request->getData('cas_number');
$query = $query->matching('Cas', function ($q) use ($cas_number) {
return $q->where([
'Cas.value LIKE' => '%'.$cas_number.'%'
]);
});
}
So far so good. If I output the SQL string it looks like this:
'SELECT DISTINCT Substances.id AS `id` FROM substances Substances INNER JOIN cas_substances CasSubstances ON Substances.id = (CasSubstances.substance_id) INNER JOIN cas Cas ON (Cas.value like :c0 AND Cas.id = (CasSubstances.cas_id))'
My problem comes with how to manipulate the query object when it comes to my article_95 table, because it's trying to join on substances.id when I need it to join on substances.app_id.
I have the following in my Table classes. Please note the line $this->setPrimaryKey('tbl_id'); - this is because I'm using a legacy/old database and the primary key of the article_95 table is actually tbl_id not id. However this is relatively insignificant because the join should be based on app_id which exists in both tables.
// src/Model/Table/SubstancesTable.php
public function initialize(array $config)
{
$this->setTable('substances');
$this->setPrimaryKey('id');
$this->hasMany('Article95s', [
'foreignKey' => 'app_id'
]);
// ...
}
// src/Model/Table/Article95sTable.php
public function initialize(array $config)
{
$this->setTable('article_95');
$this->setPrimaryKey('tbl_id');
$this->belongsTo('Substances', [
'foreignKey' => 'app_id',
'joinType' => 'INNER'
]);
}
If I try and do a search which include an Article 95 value the SQL string becomes like this:
'SELECT DISTINCT Substances.id AS `id` FROM substances Substances INNER JOIN cas_substances CasSubstances ON Substances.id = (CasSubstances.substance_id) INNER JOIN cas Cas ON (Cas.value like :c0 AND Cas.id = (CasSubstances.cas_id)) INNER JOIN article_95 Article95s ON (Article95s.entity_name like :c1 AND Substances.id = (Article95s.app_id))'
The problem with this is the part of the SQL string which reads Substances.id = (Article95s.app_id)). I need that to be Substances.app_id = (Article95s.app_id)) but I don't know how to write this with the ORM syntax.
It's also important that the rest of the joins (e.g. CAS Number shown previously) remain joined on substances.id.
Please can someone help?
the manual explain it all
belongsTo
bindingKey: The name of the column in the other table, that will be used for matching the foreignKey. If not specified, the primary key (for example the id column of the Users table) will be used.
$this->belongsTo('Substances', [
'foreignKey' => 'app_id',
'bindingKey' => 'app_id',
'joinType' => 'INNER'
]);
hasMany
bindingKey: The name of the column in the current table, that will be used for matching the foreignKey. If not specified, the primary key (for example the id column of the Articles table) will be used.
$this->hasMany('Article95s', [
'foreignKey' => 'app_id',
'bindingKey' => 'app_id',
]);

How to specify value in model relation keys?

I have tables user and profile,
one user has max one profile,
and is specified by user_id and table name in profile.
I do not use foreign keys there.
The reason I do it this way, is because I have other tables like company which also uses table profile, so reference is specified by relation_id = primary key of related table and relation = table name
profile
relation_id
relation
What I want to achieve is to set model relation to be equal to string user, so not to use key there, but to use value instead.
User.php
public function getProfile()
{
return $this->hasOne(Profile::className(),
['relation_id' => 'user_id', 'relation' => User::tableName()]);
}
Error I get:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.user' in 'on clause'
The SQL being executed was:
SELECT COUNT(*) FROM `user_login`
LEFT JOIN `user` ON `user_login`.`user_id` = `user`.`user_id`
LEFT JOIN `profile` ON `user`.`user_id` = `profile`.`relation_id`
AND `user`.`user` = `profile`.`relation`
It is for generating GridView so sql fails on count first, but error would be the same for select *
SQL I want to achieve:
SELECT * FROM `user_login`
LEFT JOIN `user` ON `user_login`.`user_id` = `user`.`user_id`
LEFT JOIN `profile` ON `user`.`user_id` = `profile`.`relation_id`
AND `profile`.`relation` = 'user'
So the question is, How to specify value in model relation keys?
if your User has a relation hasOne with profile you should use only
public function getProfile()
{
return $this->hasOne(Profile::className(),
['relation_id' => 'user_id']);
}
and if you need a on condition use
public function getProfile()
{
return $this->hasOne(Profile::className(),
['relation_id' => 'user_id'])->andOnCondition(['relation' => User::tableName()]);
}

Yii2 : LeftJoin query with Where clause & orderBy clause

I have write query to get distinct stateID whose status is active, from tbl_summer table which is primary key of table tbl_states.
I want the listing of distinct state names in alphabetical order.
Actually i got this from following query but alphabetical order is not getting...
So what is the solution...?
Here is my query :
$query = Tbl_summer::find()
->select('tbl_summer.StateID, tbl_states.state_name')
->distinct('tbl_summer.StateID')
->from('tbl_summer')
->leftJoin('tbl_states', ['tbl_states.ID' => 'tbl_summer.StateID'])
->where(['tbl_summer.IsActive' => '1'])
->orderBy(['tbl_states.state_name' => SORT_ASC]);
Does this work?
$query = Tbl_summer::find()
->select('tbl_summer.StateID, tbl_states.state_name')
->from('tbl_summer')
->leftJoin('tbl_states', ['tbl_states.ID' => 'tbl_summer.StateID'])
->where(['tbl_summer.IsActive' => '1'])
->groupBy('tbl_summer.StateID, tbl_states.state_name')
->orderBy(['tbl_states.state_name' => SORT_ASC]);
I think the second field in groupBy is not needed if there is only one name for one id.

CakePHP model and querying troubles

I'm using CakePHP 2.3.8 and I'm having trouble getting Cake to properly search for a value. It appears not to be case sensitive. I'm searching for 'User.id' and the query result it shows up as 'user.id'
users table
id | username | password | email | created
I'm trying to find the date a user was created in my ReservationController
$this->loadmodel('User');
$date = $this->User->find('first',array(
'conditions' => array(
'User.id' => $id //note: 'id' => $id gives the same results
)
));
I get the following error
Error: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'user.id' in 'where clause'
SQL Query: SELECT `User`.`created` FROM `TestDB`.`users` AS `User` WHERE `user`.`id` = 1 LIMIT 1
When I copy the query into PHPMyadmin and change 'user.id' to 'User.id' it then works. Why is Cake making the u lowercase even though I capitalize it in my query? If I change it to 'Users.id' cake will then search with an uppsercause U and adds the s, but that's not what I want.
I tried adding a primary key to my user model with public $primaryKey = 'id'; but that didn't do anything. Currently, I don't have any references for primary key in my User model so I'm not sure where/why it's deciding to search for 'user.id' even though I specifically reference 'User.id' in my search. In fact, the only thing in my user model is for form validation.
You do not need to Add modelName in Query if its for Same Model.. Retriving data
$this->loadModel('User');
$date = $this->User->find('first',array(
'conditions' => array(
'id' => $id
)
));

CakePHP & MySQL - Using find('all') with GROUP for one field and MAX for another field

I have a MySQL table with 3 columns (thread_id, message_id, message). Along the lines of the solution found under the "Example using GROUP BY" in this link, I want my query to GROUP BY thread_id, but return the line of of the highest message_id (instead of default lowest) for each thread_id. I then want a nicely formatted array with lines/items just like you get for less complex find operations in CakePHP along the lines of $array[index]['Model']['field']. Using the following CakePHP syntax:
$this->Model->find('all', array(
'fields' => array('MAX(Model.message_id) as message_id', 'Model.thread_id', 'Model.message'),
'group => 'Model.thread_id'
));
Now, unfortunately I am not getting that nicely formatted array. Instead I get an array which looks something like:
Array ( [0] => Array ( [0] => Array ( [message_id] => wanted/correct_message_id ) [Model] => Array ( [message] => Message from lowest/unwanted message_id line. [thread_id] => Key from lowest/unwanted message_id line))
Why does the message_id not get hooked onto the [Model] part of the array and why does CakePHP fetch the lowest message_id line and put the message and thread_id into the [Model] part of the array without the message_id column?
I want all thre columns in the [Model] part of the array and I want that line to be the highest message_id for that thread_id per my initial description. Hope this question makes sense.
Virtual fields are really useful for this kind of thing.
class MyModel extends AppModel {
public $virtualFields = array(
'max_message_id' => 'MAX(MyModel.message_id)'
);
}
You can now use max_message_id as if it were a normal field in your table, so you can add it to your find operations.