Zend DB Union not working - mysql

I was given the task of translating an old query into Zend and all was going well until I went to create the union. I cannot post the actual contents of the query due to company regulations but basically what I have is:
$sql1 = $db->select()
->from(array('t' => 'tableOne'), array('t.id'))
->joinLeft(array('tt' => 'tableTwo'), 'tt.fk_tableOne_id = t.id', array())
->where($db->quoteInto('tt.active = ?', 'Y'));
$sql2 = $db->select()
->from(array('t' => 'tableOne'), array('t.id'))
->joinLeft(array('tt' => 'tableTwo'), 'tt.fk_tableOne_id = t.id', array())
->where($db->quoteInto('tt.active = ?', 'Y'));
$select = $db->select()->union(array($sql1, $sql2))->order('t.id');
Now, if I do a fetchAll on $sql1, it works. If I do a fetchAll on $sql2, it works. However, when I do a fetchAll on $select I get an error 1064 Syntax Error.
The sql string echoed by echo $select is basically
(ORDER BY `t.id` ASC) UNION (SELECT ... ) UNION (SELECT ...)
With the syntax error near ORDER BY ...
It seems like this should all be working since the two queries work independently, any ideas?

I tried a slightly modified query from yours:
$sql1 = $zdb->select()
->from(array('t' => 'articles'), array('t.id'))
->joinLeft(array('tt' => 'users'), 'tt.id = t.author_id', array())
->where($zdb->quoteInto('tt.level = ?', 'editor'));
$sql2 = $zdb->select()
->from(array('t' => 'blogs'), array('t.id'))
->joinLeft(array('tt' => 'users'), 'tt.id = t.updated_by', array())
->where($zdb->quoteInto('tt.level = ?', 'editor'));
$select = $zdb->select()->union(array($sql1, $sql2))->order('id');
echo $select;
and got the following:
SELECT `t`.`id` FROM `articles` AS `t` LEFT JOIN `users` AS `tt` ON tt.id = t.author_id
WHERE (tt.level = 'editor') UNION SELECT `t`.`id` FROM `blogs` AS `t` LEFT JOIN `users`
AS `tt` ON tt.id = t.updated_by WHERE (tt.level = 'editor') ORDER BY `id` ASC
What version of the framework do you have?

Related

Trying to convert a query to eloquent

I have the following SQL:
SELECT arv.*
FROM article_reference_versions arv
INNER JOIN (SELECT `order`,
Max(`revision`) AS max_revision
FROM article_reference_versions
WHERE `file` = '12338-230180-1-CE.doc'
GROUP BY `file`,
`order`) AS b
ON arv.order = b.order
AND arv.revision = b.max_revision
WHERE arv.file = '12338-230180-1-CE.doc'
I need to convert this to Eloquent, so that I can properly access the data in object form. I tried doing it as such,
$s = Models\EloArticleReferenceVersion::select(
'SELECT arv.*
FROM article_reference_versions arv
INNER JOIN (
SELECT `order`, max(`revision`) as max_revision
FROM article_reference_versions
WHERE file = ? group by `file`, `order`) AS b
ON
arv.order = b.order AND arv.revision = b.max_revision
WHERE arv.file = ?',
[
'12338-230180-1-CE.doc',
'12338-230180-1-CE.doc'
])->get();
dd($s);
But I'm running into a plethora of issues, one after another. I figured it'd be easier to just convert this into an eloquent query, looking for some help with this.
DB Query to Query using Eloquent.
$query = EloArticleReferenceVersion::query()
->join(DB::raw('( SELECT `order`,Max(`revision`) AS max_revision FROM article_reference_versions WHERE `file` = '12338-230180-1-CE.doc' GROUP BY `file`, `order`) as sub_table'), function($join) {
$join->on('sub_table.order', '=', 'article_reference_versions.order');
$join->on('sub_table.max_revision ', '=', 'article_reference_versions.revision');
})
->where('article_reference_versions.file', '=', '12338-230180-1-CE.doc' )
->get();
Not Tested

ORM query builder for complex condition in CakePHP

I have user_messages table with columns id, sender_id, receiver_id, message, deleted
I have to retrieve all messages like this
SELECT *
FROM
user_messages UserMessages
WHERE (
UserMessages.deleted = false
AND (
(sender_id = $loggedin_user_id AND receiver_id = $user_id)
OR
(sender_id = $user_id AND receiver_id = $loggedin_user_id)
)
ORDER BY
created DESC
Currently, I'm using this query builder
$message_by_list = $this->UserMessages->find()
->where(['UserMessages.deleted' => false])
->andWhere(function ($exp) {
return $exp->or_([
'sender_id' => $this->Auth->user('id'),
'receiver_id' => $this->Auth->user('id')
]);
})
which is generating sql query as
FROM
user_messages UserMessages
WHERE
(UserMessages.deleted = false AND (sender_id = $loggedin_user_id OR receiver_id = $loggedin_user_id))
ORDER BY
created DESC
How to write optimized ORM Query to retrieve data as above?
Edit 2 : Updated query for arilia's answer
WHERE (
(
UserMessages.deleted = false
)
AND
(
(
UserMessages.sender_id = $loggedin_user_id
AND
UserMessages.receiver_id = $user_id
)
OR
UserMessages.sender_id = $user_id
OR /// doubt here
UserMessages.receiver_id = $loggedin_user_id
)
)
try this
$message_by_list = $this->UserMessages->find()
->where(['sender_id' => $user_id, 'receiver_id' => $logged_user_id])
->orWhere(['sender_id' => $logged_user_id, 'receiver_id' => $user_id])
->andWhere(['UserMessages.deleted' => false]);

How to implement ON ( ... OR ...) mysql query in doctrine2 queryBuilder

I have a SQL query in MYSQL:
For example
SELECT s.* FROM vplanning.cities as c1
INNER JOIN vplanning.cities as c2
ON (c1.id = c2.area_id)
INNER JOIN vplanning.storages as s
ON (s.city_id = c2.id OR s.city_id = c1.id)
WHERE c1.id = 109;
In doctrine I can write something like this (from my work code):
$query = $em->getRepository('VplanningPageBundle:Storage')
->createQueryBuilder('s')
->innerJoin('s.city', 'c1')
->innerJoin('c1.area', 'c2')
->innerJoin('s.storagestype', 'st')
->where('c2.id = :cityID')
->andWhere('st.typename = :storagesTypeName')
->andWhere('s.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('s.adress')
->getQuery();
As you can see, I show my relation in
->innerJoin('s.city', 'c1')
but I need also relation like
->innerJoin('s.city', 'c2')
with this condition:
ON (s.city_id = c2.id OR s.city_id = c1.id)
But it throws this error:
Error: 'c2' is already defined
c1 and c2 are the same entity and have a inner relation.
Try this:
$repository = $em->getRepository('VplanningPageBundle:Storage');
$qb = $repository->createQueryBuilder('storage');
//We can now use the expr()
$qb->join('storage.city', 'city', Join::WITH)
->join('city.area', 'area', Join::WITH, $qb->expr()->eq('area.id', ':cityID'))
->join('storage.storagestype', 'type', Join::WITH, $qb->expr()->eq('type.typename', ':storagesTypeName'))
->where('storage.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('storage.adress');
$query = $qb->getQuery();
Try smth like this
$qb = $this->getRepository('VplanningPageBundle:City')->createQueryBuilder('c');
$qb->leftJoin('c.area', 'a')
->join('c.storage', 's', Join::ON, $qb->expr()->orX($qb->expr()->eq('c.id', 's.id'), $qb->expr()->eq('a.id', 's.id')))
->innerJoin('s.storagestype', 'st')
->where('c.id = :cityID')
->andWhere('st.typename = :storagesTypeName')
->andWhere('s.active = :active')
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1,
))
->orderBy('s.adress')
->getQuery()
;
The solution of the problem was very difficult as for me, I have to study it :)
This is a answer for my question from some forum board:
$qb = $em->getRepository('VplanningPageBundle:Storage')->createQueryBuilder('storage');
$query = $qb->join('storage.city', 'city1', Join::WITH)
->leftJoin('city1.area', 'area', Join::WITH, $qb->expr()->eq('area.id', ':cityID'))
->leftJoin('storage.city', 'city2', Join::WITH, $qb->expr()->eq('city2.id', ':cityID'))
->join('storage.storagestype', 'type', Join::WITH, $qb->expr()->eq('type.typename', ':storagesTypeName'))
->where('storage.active = :active')
->andWhere($qb->expr()->orX($qb->expr()->isNotNull('city2'), $qb->expr()->isNotNull('area')))
->setParameters(array(
'cityID' => $cityID,
'storagesTypeName' => $storagesTypeName,
'active' => 1
))
->orderBy('storage.adress')
->getQuery();

How to write a complex sql query in zend2

I want to write a mySQL query like the following in zend framework 2.
How to convert it in zend Db select convention?
SELECT profiles.*,
user.email,
user.first_name,
user.last_name,
portfilio_images.profileImage,
images.url AS imgurl
FROM profiles
INNER JOIN user ON user.user_id = profiles.ownerId
LEFT JOIN (
SELECT *
FROM portfilio_images
WHERE portfilio_images.profileImage = '1'
) as portfilio_images ON portfilio_images.profileId = profiles.id
LEFT JOIN images ON images.id = portfilio_images.imageId
WHERE profiles.ownerId != '4' AND (profiles.name LIKE '%a%' OR user.first_name LIKE '%a%' OR user.last_name LIKE '%a%')
GROUP BY user.user_id
You can also use Zend\Db\Sql\Select that allows you to build complex queries programatically. See the documentation here:
http://zf2.readthedocs.org/en/release-2.1.1/modules/zend.db.sql.html#zend-db-sql-select
You could always just perform a raw query:
$sql = "SELECT * FROM test";
$statement = $abAdapter->query($sql);
$result = $statement->execute();
$resultSet = new ResultSet;
$resultSet->initialize($result);
return $resultSet;
Or if you want to add some parameters
$sql = "SELECT * FROM test where col = ?";
$statement = $dbAdapter->query($sql);
$result = $statement->execute(array(99));
$resultSet = new ResultSet;
$resultSet->initialize($result);
return $resultSet;

Wordpress query to inner join posts -> custom table -> post meta where metakey = metavalue

I need to join POSTS with CUSTOM TABLE and POSTMETA. I am keeping track of popular posts in the custom table but I only want posts returned that have a specific postmeta value.
I searched and could not find a tut.
Here is what I 'think' I should do... but it doesn't work when done by hand in phpmyadmin.
SELECT (post info) FROM posts p INNER
JOIN custom_table t ON p.ID = t.ID
INNER JOIN post_meta m ON p.ID = m.ID
WHERE m.metakey = 'mykey' AND
post_type = 'post' AND post_date <
'$now' AND post_date > '$lastmonth'
ORDER BY postcount DESC LIMIT 5");
Do I need to inner join the post meta as a separate sub query?
If I might suggest, try using WP_Query(). It'll be a bit clumsy, since you'll need to add a filter for the post date range and then remove it, but it'll otherwise be predictably functional without a three-layer SQL join.
<?php
include_once( "wp-config.php" );
function filter_date_range( $where = '' ) {
$lastmonth = date("Y-m-d 00:00:00", strtotime("-1 month"));
$where .= " and post_date<now() and post_date>'{$lastmonth}'";
return( $where );
}
add_filter( 'posts_where', 'filter_date_range' );
$q = new WP_Query(array(
"post_status" => "publish",
"post_type" => "post",
"posts_per_page" => 5,
"meta_query" => array(array(
"key" => "mykey",
"value" => "my_preferred_value"
))
));
remove_filter( 'filter_date_range' );
var_dump( $q->posts );
?>