Yii2: Query not being generated correctly - php

I have this query:
$nginSumSubquery = NginAgentDetail::find()
->select(['CLIENT_ID', 'sum(ngin_agent_detail.VALUES) as nginSum','STR_TO_DATE(OPERATION_DATE, '."'%Y-%m-%d %H:%i'".') AS data_ngin'])
->groupBy(['ngin_agent_detail.CLIENT_ID', 'data_ngin']);
$sapSumSubquery = Sap::find()
->select(['Criado_por', 'sum(sap.Val_liq_moeda) as sapValue', 'STR_TO_DATE(Data_doc, '."'%d.%m.%Y %H:%i'".') AS Data_Sap'])
->groupBy(['sap.Criado_por', 'sap.Data_doc']);
$query->select(['etu_loja.ID', 'id_master', 'nginSum', 'sapValue', 'regiao', 'etu_loja.user', 'Atendedora', 'Loja', 'Data_Sap', 'data_ngin'])
->leftJoin(['nginAgentDetail' => $nginSumSubquery], 'nginAgentDetail.CLIENT_ID = etu_loja.ID')
->leftJoin(['sap' => $sapSumSubquery], 'sap.Criado_por = etu_loja.user')
->where(['data_ngin' => 'Data_Sap']);
And the generated sql query:
SELECT
`etu_loja`.`ID`,
`id_master`,
`nginSum`,
`sapValue`,
`regiao`,
`etu_loja`.`user`,
`Atendedora`,
`Loja`,
`Data_Sap`,
`data_ngin`
FROM
`etu_loja`
LEFT JOIN
`master_loja` ON `etu_loja`.`id_master` = `master_loja`.`id`
LEFT JOIN
(SELECT
CLIENT_ID,
SUM(ngin_agent_detail.VALUES) AS nginSum,
STR_TO_DATE(OPERATION_DATE, '%Y-%m-%d') AS data_ngin
FROM
`ngin_agent_detail`
GROUP BY `ngin_agent_detail`.`CLIENT_ID` , `data_ngin`) `nginAgentDetail` ON nginAgentDetail.CLIENT_ID = etu_loja.ID
LEFT JOIN
(SELECT
Criado_por,
SUM(sap.Val_liq_moeda) AS sapValue,
STR_TO_DATE(Data_doc, '%d.%m.%Y') AS Data_Sap
FROM
`sap`
GROUP BY `sap`.`Criado_por` , `sap`.`Data_doc`) `sap` ON sap.Criado_por = etu_loja.user
WHERE
`Data_Sap` = 'data_ngin'
Why Yii add backtick to left side of the last where clause and not the right?
`WHERE
`Data_Sap` = 'data_ngin'
If i just replace the single quote by backtick in mysql workbench, i mean, 'data_ngin' to `data_ngin` the query works.
How can make this query work in Yii?

Method where() with hash format works best for cases when you want to select column's value. data_ngin is treated as string and not a column's name.
In your case you want to use string format which is more similar to the raw SQL statement.
->where('Data_Sap=data_ngin')
or if the above still doesn't work
->where('`Data_Sap`=`data_ngin`')

Related

Mysql higher LIMIT offset very slow with join in PHP

I'm trying to change mySQL query for a faster data retrieval from the server. I have a table with more than 500,000 records but it takes forever to retrieve the data.
I want to change the query from
SELECT
loanapply.loanapplyId,
loanapply.loanAmount,
loanapply.email,
loanapply.approve,
loanapply.loanDate,
mkopakenya.name,
mkopakenya.idno,
mkopakenya.phoneNo,
mkopakenya.verification
FROM
loanapply
LEFT JOIN mkopakenya ON loanapply.email = mkopakenya.email
WHERE
loanapply.approve = 'ongoing'
AND loanapply.del = 'false'
AND loanapply.archive = 0
AND loanapply.loanDate = '$date'
GROUP BY
loanapply.loanapplyId,
loanapply.loanAmount,
loanapply.email,
loanapply.approve,
loanapply.loanDate,
mkopakenya.name,
mkopakenya.idno,
mkopakenya.phoneNo,
mkopakenya.verification
ORDER BY
loanapplyId DESC
LIMIT
$currentSize,
$limit
to
SELECT
loanapply.loanapplyId,
loanapply.loanAmount,
loanapply.email,
loanapply.approve,
loanapply.loanDate,
mkopakenya.name,
mkopakenya.idno,
mkopakenya.phoneNo,
mkopakenya.verification
FROM
loanapply
LEFT JOIN mkopakenya ON loanapply.email = mkopakenya.email AS data1
INNER JOIN (
SELECT
loanapply.loanapplyId
FROM
loanapply
LIMIT
$currentSize,
$limit
) AS data2 ON data1.loanapplyId = data2.loanapplyId
WHERE
loanapply.approve = 'ongoing'
AND loanapply.del = 'false'
AND loanapply.archive = 0
AND loanapply.loanDate = '$date'
ORDER BY
loanapplyId DESC
for faster data retrieval, The second query only returns blank values
for fast data retrival first you should check for valid indexes
be sure you have a proper composite index on loanapply eg:
create index myidx on loanapply ( loanDate, archive, del, approve, email )
and
table mkopakenya column ( email)
anyway (not for better perfomance but for proper use of SQL) you should not use group by without aggregation function (this behaviour is allowed for mysql version <5.7 but, by default, produce error for version >= 5.7) if you need distinct result use DISTINCT clause
SELECT DISTINCT loanapply.loanapplyId
, loanapply.loanAmount
, loanapply.email
, loanapply.approve
, loanapply.loanDate
, mkopakenya.name
, mkopakenya.idno
, mkopakenya.phoneNo
, mkopakenya.verification
FROM loanapply
LEFT JOIN mkopakenya ON loanapply.email = mkopakenya.email
WHERE loanapply.approve='ongoing'
AND loanapply.del='false'
AND loanapply.archive=0
AND loanapply.loanDate='$date'
ORDER BY loanapplyId DESC LIMIT $currentSize, $limit

Why Codeigniter's Query Builder is returning this MySQL query wrong and twice?

I'm getting this string (raw copy and paste)
SELECT `ing_names`.`name` FROM `ingredients` INNER JOIN `ing_names` ON `ingredients`.`id_name` = `ing_names`.`id` WHERE `id_type` = '1'
SELECT `ing_names`.`name` FROM `ingredients` INNER JOIN `ing_names` ON `ingredients`.`id_name` = `ing_names`.`id` WHERE `id_type` = '1'
From this test code (in my model)
$this->db->select('ing_names.name','ingredients.stock');
$this->db->from('ingredients');
$this->db->join('ing_names','ingredients.id_name = ing_names.id', 'inner');
$this->db->where('id_type','1');
$this->db->get();
echo $this->db->last_query();
Why is query builder returning this query?
I'm trying to do this query
SELECT `ing_names`.`name`, `ingredients`.`stock`
FROM `ingredients`
INNER JOIN `ing_names`
ON `ingredients`.`id_name` = `ing_names`.`id`
WHERE `id_type` = 1
First argument to select should be a string or an array.
$this->db->select('ing_names.name, ingredients.stock');
...
//$this->db->select(['ing_names.name', 'ingredients.stock']);
Second argument to select specifies whether to escape values or not.

Yii2 translating findBySql query to QueryBuilder query

I have the following query using findbysql:
$query = Users::findBySql('select a.user_id, a.last_name,a.first_name, a.emp_id, ar.role_id from auth_users a, auth_user_roles AR, AUTH_USER_DEPTS AD, DEPARTMENTS D
where AD.DEPT_ID = D.DEPT_ID AND AR.USER_ID = AD.USER_ID and a.user_id = ar.user_id
AND D.DEPT_GROUP_ID = :dept_group_id AND (ACCESS_END_DATE > SYSDATE OR ACCESS_END_DATE IS NULL)
UNION
SELECT DISTINCT a.user_id, a.last_name, a.first_name, a.emp_id, NULL AS role_id FROM auth_users a, AUTH_USER_ROLES AR, AUTH_USER_DEPTS AD, DEPARTMENTS D
WHERE AD.DEPT_ID = D.DEPT_ID AND AR.USER_ID = AD.USER_ID and a.user_id = ar.user_id
AND D.DEPT_GROUP_ID = :dept_group_id AND
AR.ACCESS_END_DATE < SYSDATE AND AR.USER_ID NOT IN (select USER_ID from auth_user_roles where ACCESS_END_DATE > SYSDATE OR ACCESS_END_DATE IS NULL)', [':dept_group_id' => $dept_group_id ]);
This query does exactly what I want it to, but the problem is when I try to put it into a gridview it does not sort. According to Sort and search column when I'm querying with findbysql in yii2 it seems like I need to use query builder instead.
So I was trying to do that with the first part of my query (before the union), and it looks like so:
$query1 = (new \yii\db\Query())
->select(['user_id', 'last_name', 'first_name', 'emp_id'])
->from('AUTH_USERS');
$query2 = (new \yii\db\Query())
->select('USER_ID')
->from('AUTH_USER_ROLES')
->where('ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL');
$query = $query1->innerJoin('AUTH_USER_DEPTS', 'AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id')->innerJoin('DEPARTMENTS', 'AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id');
$query->innerJoin('AUTH_USER_ROLES', 'AUTH_USER_ROLES.USER_ID = auth_users.USER_ID')->where('ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL');
However, my query comes out like this in yii and apparently oracle is not accepting the double quotes around the column names:
SELECT "user_id", "last_name", "first_name", "emp_id" FROM "AUTH_USERS"
INNER JOIN "AUTH_USER_DEPTS" ON AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id
INNER JOIN "DEPARTMENTS" ON AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id
INNER JOIN "AUTH_USER_ROLES" ON AUTH_USER_ROLES.USER_ID = auth_users.USER_ID
WHERE ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL
I know the query might be incorrect here already but I cant even get the double quotes to go away. Tried defining the select statements multiple ways suggested by the yii docs already with no success:
select(['user_id', 'last_name', 'first_name', 'emp_id'])
select('user_id', 'last_name', 'first_name', 'emp_id')
select("user_id, last_name,first_name,emp_id")
I have also tried joining the queries like this from the docs: http://www.yiiframework.com/doc-2.0/guide-db-query-builder.html
$query = $query1->innerJoin(['u' => $query2], 'u.user_id = user_id');
but it also complains that it doesnèt recognize u and the query instead comes out like so in yii:
SELECT COUNT(*) FROM "AUTH_USERS" INNER JOIN "AUTH_USER_DEPTS" ON AUTH_USER_DEPTS.user_id = AUTH_USERS.user_id INNER JOIN "DEPARTMENTS" ON AUTH_USER_DEPTS.dept_id = DEPARTMENTS.dept_id INNER JOIN (SELECT "USER_ID" FROM "AUTH_USER_ROLES" WHERE ACCESS_END_DATE>SYSDATE OR ACCESS_END_DATE IS NULL) "u" ON u.user_id = auth_users.user_id
At this point im just looking for the easiest way to build this query (whether it be using querybuilder or some other way) so that I can pass the query to my gridview and sort it.
I would recommend you first create all the data models you need from the tables you need for the query, using Gii it should be easy and it even creates the relationships you will need.
After that, you can do something like the following:
$query = Users::find()
->joinWith('theRelation1Name')
->joinWith('theRelation2Name')
->joinWith('theRelation3Name')
...
This way you don't need to give tables aliases or add the conditions needed for the relations to work.

Codeigniter join query multiple conditions don't work

I want to select data from my database table with join query, but my it doesn't work.
My query:
$this->db->select();
$this->db->from('we');
$this->db->join('schedule', 'schedule.itemid = we.cid');
$this->db->join('schedule', 'schedule.itemtype = 'testitem'');
$this->db->where('we.isActive','Y');
This line makes problem with schedule.itemtype = 'testitem':
$this->db->join('schedule', 'schedule.itemtype = 'testitem'');
How can I solve this?
You don't need to join same table twice.
But just to extend ON clause:
$this->db->select();
$this->db->from('we');
$this->db->join('schedule', 'schedule.itemid = we.cid AND schedule.itemtype = \'testitem\'');
$this->db->where('we.isActive','Y');
try
$this->db->select();
$this->db->from("we");
$this->db->join("schedule", "schedule.itemid = we.cid");
$this->db->where("schedule.itemtype","testitem");
$this->db->where("we.isActive","Y");
I believe there are two problems here. The first problem is that you are using one too many quotes in the second join line in your query:
You have: $this->db->join('schedule', 'schedule.itemtype='testitem''); < extra quote
It should be: $this->db->join('schedule', 'schedule.itemtype=testitem');
Second problem: your join doesnt make sense.
Your statement:
$this->db->select();
$this->db->from('we');
$this->db->join('schedule', 'schedule.itemid = we.cid');
$this->db->join('schedule', 'schedule.itemtype = testitem');
$this->db->where('we.isActive','Y');
Translates to:
SELECT * FROM we
JOIN schedule ON schedule.itemid = we.cid
JOIN schedule ON schedule.itemtype = testitem
WHERE we.isActive = Y
As you can see you are joining the same table twice on different lines, not only that but what table does "testitem" belong to? We are left to assume that you perhaps want the join where itemtype = testitem which will mean this:
SELECT * FROM we
JOIN schedule ON schedule.itemid = we.cid
WHERE schedule.itemtype = testitem
AND we.isActive = Y
Therefore your final Codeigniter query should be:
$this->db->select('*');
$this->db->from('we');
$this->db->join('schedule', 'schedule.itemid = we.cid');
$this->db->where('schedule.itemtype', 'testitem');
$this->db->where('we.isActive','Y');
This will work:
$this->db->join('schedule', 'schedule.itemid = we.cid');
$this->db->where('we.isActive','Y');
$this->db->where('schedule.itemtype', 'testitem');
$this->db->get('we');
$this->db->query('select we_tbl.c_name from we we_tbl,schedule sch_tbl where sch_tbl.itemid = we_tbl.cid AND we_tbl.idActive = '.$activeData);
Try this query according to your problem this could get the data you need.
I've tested on different database but i tried to perform what you're trying to get. https://www.w3schools.com/sql/trysql.asp?filename=trysql_op_in
select
pro_tbl.ProductName,
cat_tbl.CategoryName ,
sup_tbl.SupplierName
from
Products pro_tbl,
Suppliers sup_tbl,
Categories cat_tbl
where
pro_tbl.SupplierID = sup_tbl.SupplierID AND
pro_tbl.CategoryID = cat_tbl.CategoryID;
Two possible problems, depending on what your desired outcome is:
If you need to make two joins and are getting an error with the second join clause, try using double quotes to enclose the constant value on the condition or you'll get a parse error:
$this->db->join('schedule', 'schedule.itemtype = "testitem"');
If you need to join only once with multiple conditions, use parentheses:
$this->db->select('*');
$this->db->from('we');
$this->db->join('schedule', '(schedule.itemid = we.cid AND schedule.itemtype="testitem")');
$this->db->where('we.isActive','Y');
You query is equivalent to writing:
select * from we
inner join schedule on schedule.itemid = we.cid
inner join schedule on schedule.itemtype = "testitem"
where we.isActive = 'Y'
but what you seem to need is
select * from we
inner join schedule on (schedule.itemid = we.cid AND schedule.itemtype = "testitem")
where we.isActive = 'Y'
On your original query, you are doing two joins. In the latter, you'll do only one with multiple conditions.

Unknown column and filter by multiple return subquery

At the moment i have this query:
$qry = "SELECT platforms.PID
FROM user_profile
LEFT JOIN platforms
ON platforms.relaccount = user_profile.subkey
WHERE user_profile.UID = `".$data['id']."`";
$games = $this->db->select('main.APPID, games_other.name, games_other.logo')
->select('platforms.PID, platforms.name AS pname, platforms.logo AS plogo')
->select('('.$qry.') AS filt', null, FALSE)
->from('games_link AS main')
->join('games_platforms', 'games_platforms.APPID = main.APPID', 'left')
->join('platforms', 'platforms.PID = games_platforms.PID', 'left')
->join('games_other', 'games_other.APPID = main.GB_ID', 'left')
->like('games_other.name', $name)
->where('platforms.PID', 'filt')
->limit(15)
->get();
Where im trying to get games based on an input string but filtered by what platforms a user has, but it returns this error:
Unknown column 'Cf9nHvOlaaLzFRegX2Il' in 'where clause'
SELECT `main`.`APPID`, `games_other`.`name`, `games_other`.`logo`, `platforms`.`PID`, `platforms`.`name` AS pname, `platforms`.`logo` AS plogo, (SELECT platforms.PID FROM user_profile LEFT JOIN platforms ON platforms.reaccount = user_profile.subkey WHERE user_profile.UID = `Cf9nHvOlaaLzFRegX2Il`) AS filt FROM (`games_link` AS main) LEFT JOIN `games_platforms` ON `games_platforms`.`APPID` = `main`.`APPID` LEFT JOIN `platforms` ON `platforms`.`PID` = `games_platforms`.`PID` LEFT JOIN `games_other` ON `games_other`.`APPID` = `main`.`GB_ID` WHERE `platforms`.`PID` = 'filt' AND `games_other`.`name` LIKE '%a%' LIMIT 15
Filename: response/update.php
I have tried changing a few things around but nothing fixes this.
Also since I Havant been able to get there yet, would this work as a filter. The sub query will return multiple.
You have a column value with backticks and its not valid it should be single quote or no quote if its INTEGER
$qry = "SELECT platforms.PID
FROM user_profile
LEFT JOIN platforms
ON platforms.reaccount = user_profile.subkey
WHERE user_profile.UID = '".$data['id']."'";
Your problem is here:
WHERE user_profile.UID = `Cf9nHvOlaaLzFRegX2Il`
Backticks, `, escape database objects (view names, table names, column names ... etc).
String values should be escaped with single quotes, '.
I would be wary of concatenating in values, you should probably bind them in if possible.

Categories