DQL innerJoin query equivalent - mysql

I have the code below working correctly on phpMyAdmin:
select testers.department from testers
inner join request_details
on testers.id = request_details.test_id
where request_details.request_id = '12345'
I tried converting it to DQL as below:
$query = Doctrine_Query::create()
->select('t.department')
->from('testers t, request_details r')
->innerJoin('t.id r')
->where('t.id = r.tester_id')
->andWhere('r.request_id = ?', 12345);
However , a var_dump() on the variable holding the query result returns NULL.

Which Doctrine version are you using, because in Doctrine2 you should be using the QueryBuilder class and you should use class names and properties, not table names and fields in DQL.
Thus, you should join to the class field name, not the table field name.
innerJoin('t.request_details', 'r') // where request_details is a propery on Tester
Also, you do not need the where that joins them (where(t.id = r.tester_id)), this is managed by Doctrine and will work provided that the entities are properly mapped.
You also do not need the request_details r in the from part, Doctrine will take care of this too.
Also, use class names in from, not table names.
EDIT (forgot the getQuery() before getResults()):
In the end you query would look something like this:
$queryBuilder = EntityManager::create(//em options)->createQueryBuilder();
$queryBuilder->select('t.department')
->from('Tester', 't')
->innerJoin('t.request_details', 'r') // request details is a propery on Tester, that maps to RequestDetails
->where('r.request_id = ?1')
->setParameter(1, 123);
Doctrine will take care of turning this into SQL and joining the thing.
In the end you'll also need to fetch the stuff:
$departments = $queryBuilder->getQuery()->getResult();
EDIT:
for Doctrine 1, something like this should work:
$q = Doctrine_Query::create()
->select('t.department')
->from('Tester t')
->innerJoin('t.request_details r') // request details is a propery on Tester, that maps to RequestDetails
->where('r.request_id = ?', 123);
$depts = $q->fetchArray();
I am not really familiar with Doctrine 1, so take a look at this for more info:
http://docs.doctrine-project.org/projects/doctrine1/en/latest/en/manual/dql-doctrine-query-language.html

Related

Cannot get MYSQL to query JSON column correctly in Laravel

I am trying to query a JSON column in MYSQL using Laravel. I cannot get it to pick up records when I know there should be.
This is my select statement if I try it directly in MySQL after extracting from Laravel:
select `resources`.*, `users`.* from `resources` inner join `users` on `resources`.`user_id` = `users`.`id` where `status_id` = 3 and `resources`.`languages`->'$.""$"'.`name"` = English
I tried cleaning it up a bit according to the MySQL documentation:
select `resources`.*, `users`.* from `resources` inner join `users` on `resources`.`user_id` = `users`.`id` where `status_id` = 3 and `resources`.`languages`->"$.name" = "English"
My actual Laravel code is this:
$query = DB::table('resources')
->join('users', 'resources.user_id', '=', 'users.id')
->select('resources.*', 'users.*')
->where('status_id', '=', 3);
if (isset($languagesearch)) $query=$query->where('resources.languages->"$.name"', $languagesearch);
if (isset($formatssearch)) $query=$query->whereRaw('JSON_EXTRACT(resources.formats, "$.name") = "'.$formatssearch.'"');
$resources = $query->get();
$resources = json_decode( json_encode($resources), true);
You I have two JSON columns and I have tried them both using two different methods but still no luck. It does set or unset the value correctly, it is just the where clause that is not working.
EDIT: The JSON Column format is: [{"name": "English"}, {"name": "German"}, {"name": "Portuguese"}]
My MySQL version is 5.7.18
The Laravel query builder just uses plain -> operators. It will convert it to the correct syntax on the back end. Your where clause should just look like:
if (isset($languagesearch)) {
$query = $query->where('resources.languages->name', $languagesearch);
}
if (isset($formatssearch)) {
$query = $query->where('resources.formats->name', $formatssearch);
}
You can read more about json where clauses in the documentation here.
This, of course, assumes you're using a supported version of MySQL (at least 5.7.9).
Edit
Because you're trying to search for a certain value inside of a json array, you will need to use the JSON_CONTAINS() function. You may want to look at the documentation for json search functions here.
With the current way your json is structured, you would need something like:
if (isset($languagesearch)) {
$query = $query->whereRaw('JSON_CONTAINS(resources.languages, \'{"name": "'.$languagesearch.'"}\')');
}

MySql Query build using Kohana's ORM

I'm having a hard time to translate the following query into kohana's ORM.
So, if I do the following works fine:
$query = DB::query(Database::SELECT, 'SELECT id_book, MATCH(title, author, isbn) AGAINST (:str) AS score FROM tab_books WHERE status = 1 AND MATCH(title, author, isbn) AGAINST (:str) HAVING score > '.$score.' ORDER BY score DESC LIMIT 100');
However, I need to use an specific class model. So far I have:
$books = new Model_Book();
$books = $books->where('status', '=', 1);
$books = $books->where(DB::expr('MATCH(`title`,`author`,`isbn`)'), 'AGAINST', DB::expr("(:str)"))->param(':str', $search_terms);
Which works fine, except for the fact that I'm unable to use the score value. I need the score because since I changed the table engine to InnoDB, the 2nd query is returning a lot of results.
ORM here: https://github.com/kohana/orm/blob/3.3/master/classes/Kohana/ORM.php
Thank you for your time.
So, you don't use query builder, but ORM object finding.
In first case you take result array on second array of objects.
Trust me, you don't want use list objects. (It's extremely slow)
$sq = DB::expr('MATCH(title, author, isbn) AGAINST (:str) AS score')
->param(":str", $search_terms);
$wq = DB::expr('MATCH(title, author, isbn)');
$query = DB::select('id_book', $sq)
->from('tab_books') // OR ->from($this->_table_name) for model method
->where('status','=',1) ->where($wq, 'AGAINST ', $search_terms)
->order_by('score', desc)->limit(100) //->offset(0)
->having('score', '>', $score);
$result = $query->execute()->as_array();
for query test:
die($query->compile(Database::instance()));
OT: Use
$books = ORM::factory('Book')->full_text($search_terms, $score);
instead $books = new Model_Book();

zend framework automatically alter queries

My database (mysql) tables use TIMESTAMP columns, and whenever I want them returned in a query, I want them to be queried as "UNIX_TIMESTAMP(columnname)".
How do you easily modify queries in zend framework to achieve this?
For example, the current code is:
select = $this->select();
$select->where('user_id = ?',$user_id);
return $this->fetchAll($select);
This eventually becomes:
select * from tablename where user_id = 42;
I want something that automatically finds the TIMESTAMP column and changes the resulting query to:
select user_id,name,unix_timestamp(created) where user_id = 42;
I know I can use a MySQL view to achieve this, but I'd rather avoid that.
Thanks.
RR
You should be able to specify the fields you want in the select using the $select->from() object.
Zend_Db_Select
You should end up with something like this.
$select = $this->select();
$select->from(
array('t' => 'tablename'),
array('user_id', 'name', 'UNIX_TIMESTAMP(created)')
);
$select->where('user_id = ?',$user_id);
return $this->fetchAll($select);
If you wanted to run an expression that doesn't have parenthese in the function, Use the Zend_Db_Expr() method to escape the query properly.

Propel ORM - Custom where clause

I'm trying to match md5(ID) to an id.
SELECT *
FROM `user` u
WHERE
MD5(`user_id`) = '66f041e16a60928b05a7e228a89c3799'
this is ID = 58
I tried something like this. I know I'm close I just don't know what I'm missing
$criteria = new Criteria();
$criteria->addAnd('md5('.User::USER_ID.')', $_REQUEST['fs'], Criteria::CUSTOM);
$user = UserPeer::doSelectOne($criteria);
Any ideas?
First of all, directly using Criteria objects is deprecated not recommended. You should use Active Query classes.
Using these classes, you will be able to write stuff like this :
UserQuery::create()
->where('md5(User.Password) = ?', $_REQUEST['fs'], PDO::PARAM_STR)
->findOne();
You'll notice that I use the PhpName both of the table and the column in the query.
EDIT : For raw conditions, the parameter type has to be specified. You'll find more information on this issue.
After lenghty T&E process I managed to get it done like this
$c = new Criteria();
$c->add(UserPeer::USER_ID, "md5(user.user_id) = \"".$_REQUEST['fs']."\"", Criteria::CUSTOM); // risk of SQL injection!!
$saved_search = UserPeer::doSelectOne($c);
For some reason PropelORM though that $_REQUEST['fs'] was name of the table rather than the value. \"" solved the problem.

Symfony Propel criteria

Is there any possible way to convert the MySQL object into criteria object? I tried this query:
select
p.disrepid,
p.subject, p.body,
c.disrepid as disrepid1,
c.subject as subject1,
c.body as body1
from discusreply as p, discusreply as c
where p.distopid=' . $this->id . '
and (c.disrepid = p.parentid or c.parentid = p.distopid)
order by p.disrepid ASC
I tried a lot for converting this query into a Criteria, But nothing happened. I want this criteria object for passing this into Pager class for completing the pagination.
$pager->setCriteria($c);.
You can use your own SQL do perform a query, but there is no automated way to turn sql into a Criteria object.
$con = Propel::getConnection(DATABASE_NAME);
$sql = "SELECT books.* FROM books
WHERE NOT EXISTS (SELECT id FROM review WHERE book_id = book.id)";
$stmt = $con->createStatement();
$rs = $stmt->executeQuery($sql, ResultSet::FETCHMODE_NUM);
$books = BookPeer::populateObjects($rs);
This bypasses Criterion objects all together. You mentioned wanting a criteria object so you could feed this into a pager. You can instead set a custom select method into your pager, which will then perform your custom query. If you need to pass a parameter into this, I would recommend extending sfPropel with your own pager class that can optionally pass parameters to your peer select methods so you don't have to use Criteria objects at all. As a quick alternative, you can do something like this, using your Criteria as a container for your select parameters:
$c = new Criteria();
$c->add(DiscussreplyPeer::ID, $myId);
$pager = new sfPropelPager();
$pager->setCriteria($c);
$pager->setPeerMethod('getReplies');
And then in your peer class:
public static function getReplies(Criteria $c) {
$map = $c->getMap();
$replyId = $map[DiscussreplyPeer::ID]->getValue();
$con = Propel::getConnection(DATABASE_NAME);
$sql = "select p.disrepid, p.subject, p.body, c.disrepid as disrepid1, c.subject as subject1, c.body as body1 from discusreply as p, discusreply as c where p.distopid=? and (c.disrepid = p.parentid or c.parentid = p.distopid) order by p.disrepid ASC";
$stmt = $con->prepareStatement($sql);
$stmt->setString(1, $replyId);
$rs = $stmt->executeQuery();
$results = array();
while ($rs->next()) {
// for example
$results['disrepid'] = $rs->getInt('disrepid');
}
return $results;
}
More tips on propel and symfony can be found at:
http://stereointeractive.com/blog/2007/06/12/propel-queries-using-custom-sql-peer-classes-and-criterion-objects/
This site will help a lot for learning to write criteria - you can use it to generate criteria code from pseudo SQL. I would also recommend grabbing the Symfony/Propel cheat sheets.
For your query in particular you will want something like this:
$c = new Criteria();
$c->addJoin(discusreply::DISREPID, discusreply::PARENTID, Criteria::INNER_JOIN);
$c->clearSelectColumns();
$c->addSelectColumn(discusreplyPeer::Disrepid);
...
$c->add(discusreplyPeer::DISTOPID, $this->id, Criteria::EQUAL);
...
$c->addAscendingOrderByColumn(discusreply::DISREPID);
I'm not sure that the Criteria system supports multiple clauses for an inner join so you may have to revert back to ad-hoc SQL for this query (if it does I would love to know how). The following code will create a ResultSet object similar to what you would get from simple database abstraction layers.
$sql = "SELECT ...";
$dbh = Propel::getConnection([DB]);
$sth = $dbh->createStatement();
$res = $sth->executeQuery($sql, ResultSet::FETCHMODE_NUM);
I don't think there is much of a disadvantage to using the ad-hoc method on a query like this since you will have to deal with ResultSet objects rather than table-specific objects when you are returning only specific columns.
You can try auto-generating the criteria from sql using this site.