Select not working in Yii CDbCriteria - mysql

I have two related table and I have to display data from both trough a join query.
I have this GridView that is "working" when i have to do the search, so that's mean if I have to search into a field from the joined table, it works and shows the right result, but I am not able to show all the column from both table.
Here is the error:
CDbCommand failed to execute the SQL statement: SQLSTATE[42S02]: Base
table or view not found: 1051 Unknown table 'pratiche'. The SQL
statement executed was: SELECT pratiche.* FROM pratiche t LEFT
JOIN clienti ON id_cliente = clienti.id LIMIT 10
As you can see there is t after pratiche, so it fail the query.
What's the problem?
public function search()
{
// #todo Please modify the following code to remove attributes that should not be searched.
$criteria=new CDbCriteria;
$criteria->select = "pratiche.*,clienti.*";
$criteria->join='LEFT JOIN clienti ON id_cliente = clienti.id';
$criteria->compare('id_pratiche',$this->id_pratiche,true);
//this is the fild that should be shown(from the joined table)
$criteria->compare('codice_fiscale',$this->codice_fiscale,true);
$criteria->select = "pratiche.*";
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}

SOLVED!
Wrong way to set the criteria:
$criteria->select=array('id_pratiche','data_creazione','stato_pratica','nome','cognome');

Related

return result from table that not existed on another table in codeignator

I've constructed two tables: one to list the services and another to link the service to each department.
Table 1 contains the columns [s id,s name]. [s_id,s_name].
-- The Services table, records all services for all departments. [1,Install Windows 10],[2,print Payslip].
Table 2 : services_assignments consist of columns [ss_id,ss_s_id_ss_d_id].
-- services_assignments matching the services with departments.
I need to return the service that "NOT" matched for the department example.
i tried to use JOIN with Where conditions in selection but not result as the following code.
function get_services_for_assign(){ // for assigmnets
$this->db->select('*');
$this->db->from('services');
if($this->uri->segment('2')) {
$this->db->join('services_assignments','services.sr_id = services_assignments.ss_s_id','left');
$this->db->where_not_in('services_assignments.ss_d_id',$this->uri->segment('2'));
}
//$this->db->where('sr_display','1');
$data=$this->db->get();
return $data->result();
}
On the other hand, I attempted to write it manually as seen below.
function get_services_for_assign(){ // for assigmnets
$dep=$this->uri->segment('2');
$query = "SELECT sr.sr_id FROM services AS sr WHERE sr.sr_id = (SELECT sa.ss_s_id FROM services_assignments AS sa WHERE sa.ss_d_id = 1)";
$this->db->query($query);
$data=$this->db->get();
return $data->result();
}
and I encountered the following error; I discovered numerous results that were similar to my problem, but I couldn't solve it.
A Database Error Occurred
Error Number: 1096
No tables used
SELECT *
Filename: C:/xampp/htdocs/townteam/system/database/DB_driver.php
Line Number: 691
I need your help to return the results services that were not used by the other department.
You have not stated which version of CodeIgniter you are using or what the expected behaviour is when no department id is passed.
This should work in both CI3 and CI4. If using CI4, you should probably use prepared statements. I could not find documentation on passing parameters into a multi-condition join with CI so I have written the query out in full.
$sql = <<<'SQL'
SELECT s.*
FROM services s
LEFT JOIN services_assignments sa
ON s.sr_id = sa.ss_s_id
AND sa.ss_d_id = ?
WHERE sa.ss_s_id IS NULL
AND s.sr_display = 1
SQL;
$this->db->query($sql, [$this->uri->segment('2')]);

How to Delete select rows from multiple tables using Join - CodeIgniter

I have three tables that I want to be able to delete select rows from, if a given condition in one of the tables is true. I am using codeigniter.
My Table Names are: Register, Profiles and Profilesmember. All 3 tables have the column "Email" which I want to Join on. One table "Register" has a unique column "is_email_verfiied" - which is either "yes" or "no". If it is "no", I want to delete the column from table "register" as well as one of the other two tables "Profiles" and "Profilesmember" depending on which contains matching entires in the 'email' column.
Here is my model:
function databaseupdate ()
{
$verified = 'no';
$tables = array('register', 'profiles', 'profilesmember');
$this->db->from ('register');
$this->db->join('profiles', 'profiles.email = register.email');
$this->db->join('profilesmember', 'profilesmember.email = register.email');
$this->db->where('register.is_email_verified', $verified);
$this->db->delete($tables);
}
It deletes the correct entry from the table "Register", but does not from the second table Profilesmember or Profiles as the case may be.
The error message I get is
"Unknown column 'register.is_email_verified' in 'where clause'".
I checked and the column "is_email_verified" is spelled correctly, and of course does exist in table Register (for clarity, this column does not exist in the other 2 tables).
The last SQL query is
"DELETE FROM profiles WHERE register.is_email_verified = 'no' "
So I changed my approach and got rid of the JOIN idea - this works:
function databaseupdate ()
{
$verified = 'no';
$tables = array('register', 'profiles', 'profilesmember');
$this->db->select('email');
$this->db->from('register');
$this->db->where('is_email_verified', $verified);
$query = $this->db->get();
$email = $query->row()->email;
$this->db->where('email', $email);
$this->db->delete($tables);
}

Query matching() causing duplicate rows and distinct() not working

I am trying to filter one table Payments by a field on the associated table Invoices.
Using the function matching() on the query object filters correctly but causes duplicate rows. It seemed like the solution was using distinct(), but calling distinct(Payments.id) results in an invalid query. I'm doing the following in a controller action.
$conditions = [
'Payments.is_deleted =' => false
];
$args = [
'conditions' => $conditions,
'contain' => ['Invoices', 'Invoices.Clients'],
];
$payments = $this->Payments->find('all', $args);
if($issuer) {
// This causes duplicate rows
$payments->matching('Invoices', function ($q) use ($issuer) {
return $q->where(['Invoices.issuer_id' => $issuer['id']]);
});
// $payments->distinct('Payments.id'); // Causes a mysql error
}
Am I correct in thinking that distinct() is what I need, and if so any idea what's missing to make it work?
I'm getting the following mysql error when uncommenting the line above:
Error: SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #8 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'InvoicesPayments.id' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
Full query:
SELECT
PAYMENTS.ID AS `PAYMENTS__ID`,
PAYMENTS.CREATED AS `PAYMENTS__CREATED`,
PAYMENTS.MODIFIED AS `PAYMENTS__MODIFIED`,
PAYMENTS.DATE_REGISTERED AS `PAYMENTS__DATE_REGISTERED`,
PAYMENTS.USER_ID AS `PAYMENTS__USER_ID`,
PAYMENTS.AMOUNT AS `PAYMENTS__AMOUNT`,
PAYMENTS.IS_DELETED AS `PAYMENTS__IS_DELETED`,
INVOICESPAYMENTS.ID AS `INVOICESPAYMENTS__ID`,
INVOICESPAYMENTS.INVOICE_ID AS `INVOICESPAYMENTS__INVOICE_ID`,
INVOICESPAYMENTS.PAYMENT_ID AS `INVOICESPAYMENTS__PAYMENT_ID`,
INVOICESPAYMENTS.PART_AMOUNT AS `INVOICESPAYMENTS__PART_AMOUNT`,
INVOICES.ID AS `INVOICES__ID`,
INVOICES.CREATED AS `INVOICES__CREATED`,
INVOICES.MODIFIED AS `INVOICES__MODIFIED`,
INVOICES.IS_PAID AS `INVOICES__IS_PAID`,
INVOICES.IS_DELETED AS `INVOICES__IS_DELETED`,
INVOICES.CLIENT_ID AS `INVOICES__CLIENT_ID`,
INVOICES.ISSUER_ID AS `INVOICES__ISSUER_ID`,
INVOICES.NUMBER AS `INVOICES__NUMBER`,
INVOICES.SUBTOTAL AS `INVOICES__SUBTOTAL`,
INVOICES.TOTAL AS `INVOICES__TOTAL`,
INVOICES.DATE_REGISTERED AS `INVOICES__DATE_REGISTERED`,
INVOICES.CURRENCY AS `INVOICES__CURRENCY`,
INVOICES.RECEIVER_NAME AS `INVOICES__RECEIVER_NAME`,
INVOICES.RECEIVER_RFC AS `INVOICES__RECEIVER_RFC`,
INVOICES.EMAIL_SENDER AS `INVOICES__EMAIL_SENDER`,
INVOICES.PDF_PATH AS `INVOICES__PDF_PATH`
FROM
PAYMENTS PAYMENTS
INNER JOIN
INVOICES_PAYMENTS INVOICESPAYMENTS
ON PAYMENTS.ID = (
INVOICESPAYMENTS.PAYMENT_ID
)
INNER JOIN
INVOICES INVOICES
ON (
INVOICES.ISSUER_ID = :C0
AND INVOICES.ID = (
INVOICESPAYMENTS.INVOICE_ID
)
)
WHERE
(
PAYMENTS.IS_DELETED = :C1
AND PAYMENTS.DATE_REGISTERED >= :C2
AND PAYMENTS.DATE_REGISTERED <= :C3
)
GROUP BY
PAYMENT_ID
ORDER BY
PAYMENTS.DATE_REGISTERED ASC
That behavior is expected, as matching will use an INNER join, and yes, grouping is how you avoid duplicates:
As this function will create an INNER JOIN, you might want to consider calling distinct on the find query as you might get duplicate rows if your conditions don’t exclude them already. This might be the case, for example, when the same users comments more than once on a single article.
Cookbook > Database Access & ORM > Query Builder > Loading Associations > Filtering by Associated Data
As the error message states, your MySQL server is configured to use the strict only_full_group_by mode, where your query is invalid. You can either disable that strict mode as mentioned by Akash prajapati (which can come with its own problems, as MySQL is then allowed to pretty much pick values of a group at random), or you could change how you query things in order to conform to the strict mode.
In your case where you need to group on the primary key, you could simply switch to using innerJoinWith() instead, unlike matching() this will not add any fields of that association to the SELECT list, and things should be fine in strict mode, as everything else is functionally dependent:
In cases where you would group on a key that would break functional dependency detection, one way to solve that could for example be to use a subquery for filtering, one that only selects that key, something along the lines of this:
$conditions = [
'Payments.is_deleted =' => false
];
$payments = $this->Payments
->find()
->contain(['Invoices.Clients']);
if($issuer) {
$matcherQuery = $this->Payments
->find()
->select(['Payments.some_other_field'])
->where($conditions)
->matching('Invoices', function ($q) use ($issuer) {
return $q->where(['Invoices.issuer_id' => $issuer['id']]);
})
->distinct('Payments.some_other_field');
$payments->where([
'Payments.some_other_field IN' => $matcherQuery
]);
} else {
$payments->where($conditions);
}
This will result in a query similar to this, where the outer query can then select all the fields you want:
SELECT
...
FROM
payments
WHERE
payments.some_other_field IN (
SELECT
payments.some_other_field
FROM
payments
INNER JOIN
invoices_payments ON
payments.id = invoices_payments.payment_id
INNER JOIN
invoices ON
invoices.issuer_id = ...
AND
invoices.id = invoices_payments.invoice_id
WHERE
payments.is_deleted = ...
GROUP BY
payments.some_other_field
)
The problem with sql_mode value in mysql so you need to set the sql_mode value as blank and then you can try and working fine for you.
SET GLOBAL sql_mode=(SELECT REPLACE(##sql_mode,'ONLY_FULL_GROUP_BY',''));
Please let me know still anything else.
I had the same issue, but was too afraid to set the sql_mode as mentioned by #Akash and also too much in a hurry to restructure the query. So I decided to use the inherited Collection method indexBy()
https://book.cakephp.org/4/en/core-libraries/collections.html#Cake\Collection\Collection::indexBy
$resultSetFromYourPaymentsQuery = $resultSetFromYourPaymentsQuery->indexBy('id');
It worked like a charm and it is DB independent.
EDIT: After some more tinkering, this might not be practical for all use cases. Replacing matching with innerJoinWith as proposed in the accepted answer will probably solve it in more generalized manner.

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()]);
}

SQL - Result consisted of more than one row

I'm still trying to make my first function, it creates without any errors, but when I try to use it, it gives me error - ERROR 1172 (42000): Result consisted of more than one row
Here's the function -
CREATE FUNCTION kontakti2 (mainigais CHAR(3))
RETURNS CHAR(100)
BEGIN
DECLARE returnthis CHAR(100);
SELECT CONCAT(Person.name, Person.lastName, Contacts.mobile, Contacts.email)
FROM Person JOIN Contacts on Contacts.Person_ID = Person.ID
JOIN ParentChild on ParentChild.parentID = Person.ID
JOIN ChildGroup ON ChildGroup.Person_ID = ParentChild.childID
WHERE ChildGroup.Group_ID = mainigais INTO returnthis;
RETURN returnthis;
END//
Here's table schema, just in case - http://www.imagesup.net/dm-713886347846.png
How can I get this function to display several rows?
It isn't possible to return multiple rows from a function in MySQL as it does not support table valued functions like in SQL server.