Multiple joins using active record with YII framework - sql

im getting stuck with active record for yii.
im using models for each table in my db.
the sql i try to get is querying and joining from 3 tables.
what i want to accomplish is the equivalent of the sql command :
SELECT location_code as stopkey, bay_no bay_no, description stop_name, route_area_code route_area_code, latitude latitude, longitude, build_code build_code, message_time message_time, ip_address ip_address, route.route_code route, make make, last_impact last_impact, impact_count impact_count, last_bootup last_bootup, bootup_count bootup_count, last_active_hour last_active_hour, last_active_day last_active_day, operator.operator_code operator_code, routes routes, bearing
FROM snapshot_stop_status route
JOIN route_visibility ON route.route_id = route_visibility.route_id
JOIN operator ON operator.operator_id = route_visibility.operator_id
WHERE usernm = 'me'
ORDER BY location_code
here is what i tried so far :
public function relations() {
return array(
'RoutesVisibility' =>array(self::MANY_MANY,'route_visibility','route_id'),
);
}
How can i accomplish this using relations function in the models ?
any kind of help would be appreciated

route_visibility is the joining table that tie operator to snapshot_stop_status. So in yii you can specify the table doing the relations:
'operators' =>array(self::MANY_MANY,'Operator','route_visibility(route_id,operator_id )'),
And in Operator:
'routes' =>array(self::MANY_MANY,'Route','route_visibility(operator_id, route_id)'),
Then you can request with something like:
$criteria = new CDbCriteria;
$criteria->with = array('operators' => array('condition' => 'usernm = "me"'));
$models => Route:model()->findAll($criteria);

Related

Yii2: how to use subquery with ActiveRecord?

I want to create a find function to use then in a GridView widget My I don't know how to use a subquery.
This is the simple version of the PostgreSQL query that I have:
SELECT color
FROM cars
LEFT JOIN (
SELECT name
FROM companies
)
Here is what I a trying and doesn't work:
$query = Cars::find()
->select([
'color' => '
SELECT name // Problem here.
FROM companies // Problem here.
',
]);
Your expected query is not what you are trying to do. You can add a custom subquery as
$query = Cars::find()
->select([
'(SELECT name FROM companies) AS xxx'
]);
But if you want to add a field from joined table to the grid, then you should have a relation defined and then you can easily add such a column to your grid. See https://www.yiiframework.com/doc/guide/2.0/en/db-active-record#relational-data
You can use instance of ActiveQuery in leftJoin() method like this:
$subQuery = Companies::find()
->select('name', 'id'); //I've added ID to show how to write on condition
$query = Cars::find()
->select('color')
->leftJoin(
['alias' => $subQuery],
'alias.id = cars.company_id'
);
See documentation for more details about leftJoin() and join() methods.
$query = Cars::find()
->select(['cars.color','companies.name'])
->leftJoin('companies', 'cars.company_id = companies.id');

"andFilterWhere" work proper with "joinWith()" but not with "with()" in yii2

I am working in yii2.
There are employee and company table employee contains company_id.
I have a filter search running properly If I use joinWith()
$query = Employee::find();
$query->joinWith(['company']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
'sort' => false,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
//and below is the filterwhere
$query->andFilterWhere(['like', 'company.name', $this->company_id]);
But issue came when I make a query using with()
$query = Employee::find()->with(['company']);
$dataProvider = new ActiveDataProvider([
'query' => $query,
'pagination' => false,
'sort' => false,
]);
if (!($this->load($params) && $this->validate())) {
return $dataProvider;
}
//when query contain with() then this filter is not working.
$query->andFilterWhere(['like', 'company.name', $this->company_id]);
This gives error when I use with()
Database Exception – yii\db\Exception
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'company.name' in 'where clause'
The SQL being executed was: SELECT COUNT(*) FROM `employee` WHERE `company`.`name` LIKE '%1%'
Here is the relation in employee with company:
public function getCompany(){
return $this->hasOne(Company::className(), ['id'=> 'company_id']);
}
Can anyone help me or guide me how could I filter data properly using with() in a query?
Thanks.
You can't swap joinWith() and with() methods when you need to filter by the column from the related table. That's because these methods does completely different things.
Methods like joinWith() and join() actually modifies the query to add the "JOIN" part to the SQL query. The with in joinWith allows you to specify the joined table by the relation definition in the model. The eager loading in joinWith is only side effect and you can even turn that off by passing false as second parameter.
When you do:
Employee::find()->joinWith(['company'])->all();
The query that is run looks like:
SELECT * FROM employee LEFT JOIN company ON (...)
On the other side the method with() doesn't modify the query itself. It only forces the eager loading of related models. In reality the second query is used for preloading the related records.
When you do:
Employee::find()->with(['company'])->all();
It actually runs queries like these:
SELECT * FROM employee;
SELECT * FROM company WHERE id IN (...company ids selected in first query...);
So when you try to do:
$query = Employee::find()
->with(['company'])
->andFilterWhere(['like', 'company.name', $this->company_id])
->all();
The generated query is
SELECT * FROM employee WHERE company.name LIKE ...

CakePHP - add custom SQL to a Query object

I'm using CakePHP 3.5.13 to build an application which has 4 separate databases.
The main database (Datasource default in config/app.php) for the application has been baked. It was a legacy database, and the naming conventions are not written according to the way CakePHP specifies. Nonetheless it works, after going through the Models and editing things.
In a controller I have the following:
$substances = TableRegistry::get('Substances');
$query = $substances->find()->limit(250)->offset(0);
$query->select(['id', 'app_id', 'name']);
$query->contain([
'Cas' => [
'sort' => ['Cas.id' => 'ASC']
]
]);
$query->contain([
'Ecs' => [
'sort' => ['Ecs.id' => 'ASC']
]
]);
If I var_dump($query) I get an SQL string as follows:
SELECT Substances.id AS `Substances__id`,
Substances.app_id AS `Substances__app_id`,
Substances.name AS `Substances__name`
FROM substances Substances LIMIT 250 OFFSET 0
I need to modify this so the query contains an INNER JOIN to a table which is stored in one of the other databases (Datasource sdb5_tmpdata in config/app.php). The SQL I need is as follows:
SELECT Substances.id AS `Substances__id`,
Substances.app_id AS `Substances__app_id`,
Substances.name AS `Substances__name`,
Substances.date AS `Substances__date`
FROM substances Substances
INNER JOIN `sdb5_tmpdata`.`searching_1745` AS tf
ON tf.id = Substances.id LIMIT 250 OFFSET 0;
The difference between the above query and original is the following SQL:
INNER JOIN `sdb5_tmpdata`.`searching_1745` AS tf
ON tf.id = Substances.id
I don't have a corresponding Model for the table 'searching_1745' because these tables are dynamically created (and later dropped) on a database which holds "temporary" user data.
Is it possible to modify the query object, $query, such that I can introduce the custom SQL that does the inner join?
I have tried $query = $query->newExpr()->add('INNER JOIN 'sdb5_tmpdata'.'searching_1745' AS tf ON tf.id = Substances.id'); but it doesn't work.
the query builder let you build the query as you like it. It does not matter if you don't have a Table Object for that table
$query->join([
'tf ' => [
'table' => 'sdb5_tmpdata.searching_1745',
'type' => 'INNER',
'conditions' => 'tf.id = Substances.id',
]);
see here
I don't know if you can modify the query object, but tou can always write your own custom queries:
use Cake\Datasource\ConnectionManager;
$conn = ConnectionManager::get('default');
$query = $conn->query('query goes here');
for more info, read: https://book.cakephp.org/3.0/en/orm/database-basics.html#executing-queries

TYPO3 doesn't respect field names in JOIN query

I'm trying to fetch a JOIN query in TYPO3 using createQuery and $query->statement(...), but get odd results. Can someone explain to me why TYPO3 doesn't include table names as a prefix to column names in a JOIN query? Does this conflict with the ORM? Can I in anyway speed up a query of multiple 1:N-relations?
Example:
SELECT
client.name, project.name
FROM
client
LEFT JOIN
project ON project.client = client.uid
The PHP code from client repository:
$query = $this->createQuery();
$query->statement($statement);
$query->getQuerySettings()->setReturnRawQueryResult(true);
var_dump($query->execute());
The result prints out only names of the projects:
array (size=294)
0 =>
array (size=1)
'name' => string 'Projectname1' (length=21)
1 =>
array (size=1)
'name' => string 'Projectname2' (length=20)
2 =>
array (size=1)
'name' => string 'Projectname3' (length=32)
EDIT: This might be standard SQL behaviour.
Use aliases for fields:
SELECT
client.name client_name, project.name project_name
FROM
client
LEFT JOIN
project ON project.client = client.uid

Struggle with SQL Statement (Not Exists)

Hey i have some problems with a sql statement. This is the Database Scheme:(http://docs.elgg.org/wiki/DatabaseSchema), only the "entities" and the "relationship" table are important! What i'm trying to do is, select all guid's where the type of the object is "group" but this object is not a child of a other group. That means there is no record in the relationship table with the guid in the guid_two column. My first idea was this:
SELECT * FROM elgg_entities e
JOIN elgg_entity_relationships r ON e.guid = r.guid_one
WHERE e.type='group' AND NOT EXISTS (
SELECT *
FROM elgg_entity_relationships s
WHERE e.guid = s.guid_two
AND s.relationship='subgroup')
But it wont work. Also there are some other relationships in the table like member etc. I hope someone can help me, because i really frustrated right now.
Edit: This SQL query works in MyPHP, in elgg i tried to convert it into "elgg-ich":
$options = array(
'type' => 'group',
'joins' => array("JOIN elgg_entity_relationships r ON e.guid = r.guid_one"),
'wheres' => array("e.type='group' AND not exists (SELECT e.guid
FROM elgg_entity_relationships s
where e.guid = s.guid_two
AND s.relationship = 'subgroup'
)"),
'limit' => $limit,
'full_view' => FALSE,
);
$content = elgg_list_entities($options);
=> Solution was the case sensitivity and where instead of wheres in line 6.
As noted in the edited question;
Solution was the case sensitivity and where instead of wheres in line
6.