CakePHP - add custom SQL to a Query object - orm

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

Related

Cakephp 3 join satetment with where clause

I have a CakePHP API backend service and I want to add a new service that queries a database with the following SQL query:
SELECT
cs.number,
cs.date,
relation_vs_cs.relation_vs_cs_id,
relation_vs_cs.vr_id,
relation_vs_cs.cn_id,
vs.vr_id,
vs.first_name,
vs.last_name,
vs.document_id
FROM cs
INNER JOIN relation_vs_cs
ON relation_vs_cs.cn_id = cs.cn_id
INNER JOIN vs
ON relation_vs_cs.vr_id = vs.vr_id
WHERE vs.document_id = 'O416680668750'
So i do something like this in CakePhp side but it didn't work for me :
$options['conditions'] = array(
'Vs.document_id' => $vrIdByDocumentId);
$options['joins'] = array(
array('table' => 'relation_vs_cs',
'alias' => 'Relationvscs',
'type' => 'INNER',
'conditions' => array(
'Relationvscs.cn_id = Cs.cn_id')
),
array(
'table' => 'vs',
'alias' => 'Vs',
'type' => 'INNER',
'conditions' => array(
'Relationvscs.vr_id = Vs.vr_id')
));
$cnTable = TableRegistry::get("Cs");
$queryResult = $cnTable->find('all', $options)
When I sent a request using postman I got the following error :
"message": "SQLSTATE[42S22]: Column not found: 1054 Unknown column 'vs.document_id' in 'where clause'",
Could you please help Thank you in advance
The option is named join (singular), not joins, just like the corresponding query builder method.
I would also suggest that you look into setting up associations for your relationships, which would then allow you to use the innerJoinWith() and leftJoinWith() methods (among others), making your query building much easier.
Also note that you need to manually specify the fields the fields that you want to select from the joins.
See also
Cookbook > Database Access & ORM > Retrieving Data & Results Sets > Using Finders to Load Data
Cookbook > Database Access & ORM > Associations - Linking Tables Together
Cookbook > Database Access & ORM > Query Builder > Loading Associations

"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 ...

Sugar query syntax error in SugarCRM

I am trying to join table prospects with leads. I am executing this query
$queryProspects = new SugarQuery();
$queryProspects->from(BeanFactory::getBean('Prospects'));
$leads = $queryProspects->joinTable('leads');
$queryProspects->select("prospects.id","prospects.lead_id");
$queryProspects->where()->equals("lead_id","117c3d5d-07d9-0ae7-5610-573ac87c9a35");
Before executing it like this.
$queryProspects->execute();
I am compiling my query like
$queryProspects->compileSql();
This query is not working after executing. query result after compiling is
SELECT prospects.id id, prospects.lead_id lead_id FROM prospects JOIN leads ON () WHERE prospects.deleted = 0 AND prospects.lead_id = '117c3d5d-07d9-0ae7-5610-573ac87c9a35'
I know the error is () WHERE which I need to remove, but unable to do changes in sugar query in order to remove these brackets and where clause (which are showing in sql generated query).
Change from and join statement like this.
$queryProspects->from(BeanFactory::getBean('Prospects'), array('team_security' => false));
$leads = $queryProspects->join('lead')->joinName();
lead in join is the link (name field) in your prospects > vardefs.php as shown below.
'lead' => array(
'name' => 'lead',
'type' => 'link',
'relationship' => 'lead_prospect',
'module' => 'Leads',
'source' => 'non-db',
'vname' => 'LBL_LEAD',
),
please execute your query like this :
$result = $queryProspects->execute();
For more details Follow this link :
Sugar Query

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.