create zf2 query 'not in' clause using uninon - php

I want to use union queries result in Not in in ZF2. Result of this query will return
Query: $selectLevelTwoPointFive->combine($selectLevelAll, 'UNION');
Result: ( SELECT `assigned`.`item_id` AS `item_id` FROM `assign_items_level_twopointfive` AS `assigned` ) UNION ( SELECT `assigned`.`item_id` AS `item_id` FROM `assign_items` AS `assigned` )
Now I want to use this query's result in 'not in' clause.
$select = $sql->select()->from(array(
"items" => "cu_items"
))->columns(array('item_name'=> new \Zend\Db\Sql\Expression(" group_concat(`items`.`item_name`)") ));
$select->join(array(
"ca" => "cu_areas"
), new Expression(" ca.area_id = items.area_id ")
, array(
'area_name'
), $selectLevelAll::JOIN_INNER);
$select->where->addPredicate(new \Zend\Db\Sql\Predicate\Expression('items.item_id NOT IN (?)',
array($selectLevelTwoPointFive)));
The result is:
SELECT group_concat(`items`.`item_name`) AS `item_name`, `ca`.`area_name` AS `area_name` FROM `cu_items` AS `items` INNER JOIN `cu_areas` AS `ca` ON ca.area_id = items.area_id WHERE `items`.`is_opted` = 'yes' AND `ca`.`is_opted` = 'yes' AND items.item_id NOT IN ((( SELECT `assigned`.`item_id` AS `item_id` FROM `assign_items_level_twopointfive` AS `assigned` ) UNION ( SELECT `assigned`.`item_id` AS `item_id` FROM `assign_items` AS `assigned` )))
It is showing mysql error :
Error Code: 1064. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'UNION ( SELECTassigned.item_idASitem_idFROMassign_itemsASassigne' at line 1`
My required query is:
SELECT group_concat(items.item_name) AS item_name, ca.area_name AS area_name FROM cu_items
AS items INNER JOIN cu_areas AS ca ON ca.area_id = items.area_id
WHERE items.is_opted = 'yes' AND ca.is_opted = 'yes' AND items.item_id NOT IN
(
(
SELECT assigned.item_id AS item_id FROM assign_items_level_twopointfive AS assigned
UNION ( SELECT assigned.item_id AS item_id FROM assign_items AS assigned )
)
)
Actually when i use combine() it adds round bracket (first query) union (second query) But in not I need first query union second query.
Please help. If any one suggest the mysql changes it also fine.

Thanks God, Find the page.
We need to override the setSpecification()
Here is the link for the answer.
we can override the query output

Related

MERGE INTO USING from dual (ORA-00923 FROM keyword not found where expected)

My query below was working, I swear... now suddenly, it's dead, outputting 'ORA-00923 FROM keyword not found where expected'.. I cannot understand why... I have tried various linters and syntax checkers; I am simply iterating through array data and pushing to a oracle table/row - adding a new entry if table_id is not found, and updating table_id if it is found. What am I missing?
Data coming in is perfect too.. what am I doing incorrectly..
$fd = json_decode($df, true);
foreach ($fd as $key=>$data) {
var_dump($data);
$sql = "MERGE INTO app.table a
using (SELECT '${data[0]}' table_id,
'${data[1]}' fac_ident,
'${data[2]}' lg_name,
'${data[3]}' basic_tp,
'${data[4]}' catc_vd,
'${data[5]}' address,
'${data[6]}' assoc_city,
'${data[7]}' latitude,
'${data[8]}' longitude,
'${data[9]}' assoc_cnty,
'${data[10]}' assoc_st,
'${data[11]}' time_zone,
FROM dual) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident,
a.lg_name = p.lg_name,
a.basic_tp = p.basic_tp,
a.catc_vd = p.catc_vd,
a.address = p.address,
a.assoc_city = p.assoc_city,
a.latitude = p.latitude,
a.longitude = p.longitude,
a.assoc_cnty = p.assoc_cnty,
a.assoc_st = p.assoc_st,
a.time_zone = p.time_zone,
WHEN NOT matched THEN
INSERT (table_id,
fac_ident,
lg_name,
basic_tp,
catc_vd,
address,
assoc_city,
latitude,
longitude,
assoc_cnty,
assoc_st,
time_zone)
VALUES (p.table_id,
p.fac_ident,
p.lg_name,
p.basic_tp,
p.catc_vd,
p.address,
p.assoc_city,
p.latitude,
p.longitude,
p.assoc_cnty,
p.assoc_st,
p.time_zone)";
..........
If your data contains a single quote then you are doing the equivalent of trying to perform an SQL injection attack.
Don't use variable parsing ${data[0]}; instead create your query using bind variables and pass in your data properly so you are not vulnerable to SQL injection attacks.
For example:
If you have the table:
CREATE TABLE table_name (
table_id VARCHAR2(100),
fac_ident VARCHAR2(100)
)
And you have a table_id of 1 and a fac_ident of 2 then your merge would be:
MERGE INTO table_name a
USING (
SELECT '1' table_id,
'2' fac_ident
FROM dual
) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident
WHEN NOT matched THEN
INSERT (table_id, fac_ident )
VALUES (p.table_id, p.fac_ident );
This works.
However, if fac_ident has the value This value has a 'quote' inside it. then your query is:
MERGE INTO table_name a
USING (
SELECT '1' table_id,
'This value has a 'quote' inside it.' fac_ident
FROM dual
) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident
WHEN NOT matched THEN
INSERT (table_id, fac_ident )
VALUES (p.table_id, p.fac_ident );
And fails with:
ORA-00923: FROM keyword not found where expected
More insidious, is if fac_indent has the value '||(SELECT secret_column FROM secret_data WHERE ROWNUM = 1)||' and then your query becomes:
MERGE INTO table_name a
USING (
SELECT '1' table_id,
''||(SELECT secret_column FROM secret_data WHERE ROWNUM = 1)||'' fac_ident
FROM dual
) p
ON ( a.table_id = p.table_id )
WHEN matched THEN
UPDATE SET a.fac_ident = p.fac_ident
WHEN NOT matched THEN
INSERT (table_id, fac_ident )
VALUES (p.table_id, p.fac_ident );
And, if the table SECRET_DATA exists and has the column SECRET_COLUMN then your query won't fail and users can start to do unexpected things with your query. Please don't let them do this and use best practice of formulating your queries using bind variables rather than string concatenation.
db<>fiddle here

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

Koahana framework, query builder

I've pure sql query like this:
SELECT concat(tyres, '-', engine, '-', body) as product, `date`, `type`, `note`
FROM `products` LEFT JOIN `shop`.`users` ON `user_id` = `shop`.`user`.`id`
and, I using Kohana query builder in following example
DB::select(array(DB::expr('concat(tyres, engine, body)'), 'product'))->from('products')->join('shop'.'users','LEFT')->on('user_id', '=', 'shop.users.id');
so, kohana's query not working. Please help
You can always use debugging to find out error.
You are join condition is wrong you need single string to enter database name and table name.
Replace join('shop'.'users','LEFT') with join ( 'shop.users', 'LEFT' )
$query = DB::select ( array (
DB::expr ( 'concat(tyres, engine, body)' ),
'product'
) )->from ( 'products' )->join ( 'shop.users', 'LEFT' )->on ( 'user_id', '=', 'shop.users.id' );
echo Debug::vars ( $query->compile () );
Here is out put:
string(125) "SELECT concat(tyres, engine, body) AS `product` FROM `products` LEFT JOIN `shop`.`users` ON (`user_id` = `shop`.`users`.`id`)"

Laravel 4 union generate wrong SQL

Here is the code:
$f = DB::table("topics")
->join("recommends", "topics.id", "=", "recommends.courseid")
->where("recommends.re_type", "=", $re_type)
->where("recommends.re_location", "=", $re_location)
->orderBy("recommends.weigh", "desc");
$s = DB::table("topics")
->orderBy("topics.create_time", "desc");
$f->union($s)->get();
I got a wrong SQL around key word union:
select * from `topics` inner join `recommends`
on `topics`.`id` = `recommends`.`courseid`
where `recommends`.`re_type` = ?
and `recommends`.`re_location` = ?
order by `recommends`.`weigh` desc
union //here!!!!!
select * from `topics` order by `topics`.`create_time` desc
The error info:
SQLSTATE[HY000]: General error: 1221
Incorrect usage of UNION and ORDER BY (SQL: ...)
(Bindings: array ( 0 => 3, 1 => 7, ))
What is the problem?
MySQL UNIONs expect the same columns in all statements. Because you're joining another table in $f, the columns between the two statements don't match.
See MySql SELECT union for different columns?
In this case, it might be less of a headache to use the PDO object directly.
$pdo = DB::connection()->getPdo();
Found another problem with your query. You should relocate your first order by clause:
->orderBy("recommends.weigh", "desc");
It is producing the order by you before union and MySQL will not accept that.

Zendframework Union Issue

I have this code running
$sq = $this->_codes->getAdapter()->select()
->from (array('cs' => 'code_statuses'), array('total' => 'count(*)'))
->join (
array ('c' => 'codes'), 'c.code_id = cs.code_id',
array ('human_state' => new Zend_Db_Expr("CASE c.state_id WHEN 3 THEN 'active' WHEN 5 THEN 'suspended' ELSE 'inactive' END"), 'c.*')
)
->group('cs.code_id');
$sqtemp = $this->_codes->getAdapter()->select()
->from (array('cs' => 'code_statuses'), array('total' => 'count(*)'))
->join (
array ('c' => 'codes'), 'c.code_id = cs.code_id',
array ('human_state' => new Zend_Db_Expr("CASE c.state_id WHEN 3 THEN 'active' WHEN 5 THEN 'suspended' ELSE 'inactive' END"), 'c.*')
)
->group('cs.code_id');
if (!empty($options['state_id'])):
if (is_array($options['state_id'])):
$states = 'cs.state_id=' . implode(' OR cs.state_id=', $options['state_id']);
$sq->where($states)
->having(total<=4);
$sqtemp->where ('cs.state_id=5')
->having(total<4);
else:
$sq->where ('cs.state_id=?', $options['state_id']);
endif;
The issue occurs when i try to use union
$sqfinal=$this->_codes->getAdapter()->select()
->union(array($sq,$sqtemp))
->order('cs.code_id');
but individually $sq and $sqtemp work fine
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'cs.code_id' in 'order clause'
Not sure where I am going wrong
Any help will be appreciated
*edit
SELECT count(*) AS `total`,
CASE c.state_id
WHEN 3 THEN 'active'
WHEN 5 THEN 'suspended'
ELSE 'inactive'
END AS `human_state`, `c`.*
FROM `code_statuses` AS `cs`
INNER JOIN `codes` AS `c`
ON c.code_id = cs.code_id
WHERE (cs.state_id=1 OR cs.state_id=2 OR cs.state_id=4)
GROUP BY `cs`.`code_id` HAVING (total<=4)
UNION
SELECT count(*) AS `total`,
CASE c.state_id
WHEN 3 THEN 'active'
WHEN 5 THEN 'suspended'
ELSE 'inactive'
END AS `human_state`, `c`.*
FROM `code_statuses` AS `cs`
INNER JOIN `codes` AS `c`
ON c.code_id = cs.code_id
WHERE (cs.state_id=5)
GROUP BY `cs`.`code_id`
HAVING (total<4)
The part before the union is $sq, the part afterwards is $sqtemp, the combination of the two gives the print out above
Both of them with union in is the whole thing
After a second look at your code, I suspect the oder() call on the union. You're ordering by cs.code_id, whic is not mentioned in any of the select statements, nor is the c.code_id for that matter.
Try adding either c.code_id or cs.code_id to the SELECT't that make up the UNION, possibly consider using an alias, which you can then use in your order clause.
$sq = $this->_codes->getAdapter()->select()
->from(array('cs' => 'code_statuses'),
array(
'total' => 'count(*)'
'cscodeids' => 'code_ids',
));
//...
$union = $this->_codes->getAdapter()
->select()
->union(array($sq,$sqtemp))
->order('cscodeids');
This, I believe, should work. I've taken inspiration from various places. Here are some of the links that lead up to my answer (can't find all of them ATM):
MySQL union and order by help
Every derived table must have its own alias - error from combination descending MySQL
Using union and order by clause in mysql
How to use union in zend db
Zend_Db union issue: old bug report... contains some details

Categories