Zend_Db_Select: Working with JOIN's - php

I have this query:
SELECT
groups.name
categories.name,
categories.label
FROM
groups
JOIN
categories
ON
(categories.group1 = groups.id
OR
categories.group2 = groups.id)
AND
groups.label = :section
AND
categories.active = 1
Now, this is my JOIN using Zend_Db_Select but it gives me array error
$select->from($dao, array('groups.name', 'categories.name', 'categories.label'))
->join(array('categories', 'categories.group1 = groups.id OR categories.group2 = groups.id'))
->where('groups.label = ?', $group)
->where('categories.active = 1');
My error:
Exception information:
Message: Select query cannot join with
another table
Does anyone know what I did wrong?
UPDATE / SOLUTION:
I've found the solution thanx to Eran. I just post the solution here in case anyone else is stuck on a problem like this one. The solution is:
$db = Zend_Registry::get('db');
$dao = new Default_Model_Db_CategoryDao('db');
$select = $dao->select();
$select->setIntegrityCheck(false)
->from(array('c' => 'categories'), array('name', 'label'))
->join(array('g' => 'groups'), 'c.group1 = g.id OR c.group2 = g.id', 'g.label')
->where('g.label = ?', $group)
->where('c.active = 1');
return $dao->fetchAll($select);

You are using a Zend_Db_Table_Select object. Those by default have integrity check enabled and cannot select data that is outside of their table.
You can turn it off by adding -> setIntegrityCheck(false) to the select object before querying with it.
You can read more about it in the manual under Select API -> Advanced usage

Related

Doctrine Paginator with NativeQuery

I'm trying to use Doctrine Paginator, but I'm HAVING TO use NativeQuery since I use a custom DB function in my Query.
But I get this error:
Fatal error: Uncaught Error: Call to undefined method Doctrine\ORM\NativeQuery::getFirstResult()
My code so far is:
$sql = "SELECT std_modulos_aulas.idaula, std_modulos_aulas.idmodulo, conteudo, std_modulos_aulas.titulo
FROM uov.std_modulos_aulas
INNER JOIN uov.std_modulos ON std_modulos_aulas.idmodulo = std_modulos.idmodulo
INNER JOIN uov.std_cursos ON std_cursos.idcurso = std_modulos.idcurso
WHERE std_modulos.publicar = 's' AND std_modulos.excluido = 'n' AND std_modulos_aulas.publicar = 's' AND std_cursos.idcurso = ".$curso." AND academico.strip_tags(LOWER(std_modulos_aulas.conteudo)) LIKE '".$termo."'
ORDER BY std_modulos.ordem ASC, std_modulos_aulas ASC";
$rsm = new ResultSetMapping;
$rsm->addScalarResult('idaula', 'idaula');
$rsm->addScalarResult('idmodulo', 'idmodulo');
$rsm->addScalarResult('conteudo', 'conteudo');
$rsm->addScalarResult('titulo', 'titulo');
$query = $this->em->createNativeQuery($sql, $rsm);
return new Paginator($query, $fetchJoinCollection = false);
Any help would be nice. I've already tried using QueryBuilder, but my strip_tags function isn't working in that way. The old topics couldn't help me.
For those who might have the same problem in the future:
I ended up solving this by:
At my Model, I returned a standard query result:
$sql = "SELECT std_modulos_aulas.idaula, std_modulos_aulas.idmodulo, conteudo, std_modulos_aulas.titulo
FROM uov.std_modulos_aulas
INNER JOIN uov.std_modulos ON std_modulos_aulas.idmodulo = std_modulos.idmodulo
INNER JOIN uov.std_cursos ON std_cursos.idcurso = std_modulos.idcurso
WHERE std_modulos.publicar = 's' AND std_modulos.excluido = 'n' AND std_modulos_aulas.publicar = 's' AND std_cursos.idcurso = ".$curso." AND academico.strip_tags(LOWER(std_modulos_aulas.conteudo)) LIKE '".$termo."'
ORDER BY std_modulos.ordem ASC, std_modulos_aulas ASC";
$rsm = new ResultSetMapping;
$rsm->addScalarResult('idaula', 'idaula');
$rsm->addScalarResult('idmodulo', 'idmodulo');
$rsm->addScalarResult('conteudo', 'conteudo');
$rsm->addScalarResult('titulo', 'titulo');
$query = $this->em->createNativeQuery($sql, $rsm);
return $query->execute();
And then, at my Controller, I used a Zend Paginator:
$iteratorAdapter = new \Zend\Paginator\Adapter\ArrayAdapter($result);
$paginator = new \Zend\Paginator\Paginator($iteratorAdapter);
$paginator->setCurrentPageNumber($page);
$paginator->setItemCountPerPage(10);

PHP Zend Joininner

I have a SQL statement
select a.username
from friendships f1
inner join friendships f2 on (f1.user = f2.friend and f1.friend = f2.user)
inner join users a ON (a.user_id = f1.friend) where f1.user = '24'
I excuted this query on phpmyadmin and it's OK.
But I don't knoe how to do this query in Zend
$select = $this->_db_table->select()
->setIntegrityCheck(false)
->from(array('f1' => 'friendships'), array('u.*'))
->joinInner(array('f2' => 'friendships'),
array('f1.user = f2.friend', 'f1.friend = f2.user'))
->joinInner(array('u' => 'users'), array('u.user_id = f1.friend'))
->where('f1.user = ?', $user_id);
I use this code but it doesn't work, any ideas?
What version of ZF are you using ? Here is how you would do it in ZF 1.12:
$this->_db_table->getAdapter()->select()
->from("friendships as f1")
->joinInner("friendships as f2", "f1.user = f2.friend AND f1.friend = f2.user")
->joinInner("users as a", "a.user_id = f1.friend", array("a.username"))
->where("f1.user = ?", $user_id)
->query()
->fetchAll(); // use ->fetch() if you only want to retrieve one record
Read more on in the manual:
What exactly doesn't work? Are you getting a PHP/Zend error or a SQL error?
You can use $select->assemble() to examine the prepared query and compare it against your expectation:
echo $select->assemble();

Zend DB select only 1 table with multiple joins

I'm using Zend DB to generate a query using the following code:
$table->select()
->setIntegrityCheck(false) //required for multi-table join
->from('modules')
->joinInner(
'basket_modules',
'modules.id = basket_modules.id')
->joinInner(
'baskets',
'baskets.id = basket_modules.basket_id')
->where('baskets.id = ?', $this->id);
This generates the SQL:
SELECT modules.*, basket_modules.*, baskets.*
FROM modules
INNER JOIN basket_modules ON modules.id = basket_modules.id
INNER JOIN baskets ON baskets.id = basket_modules.basket_id
WHERE (baskets.id = '3')
My problem here is with the SELECT part, it's selecting all 3 tables instead of just modules, which is the one I want. So the query I would want to generate is:
SELECT `modules`.*
FROM `modules`
#etc...
How can I do this? If I edit the query manually and run it, it returns what I want so there shouldn't be a problem with the syntax.
Please look at the example in the manual Zend_Db_Select. Scroll to the Example #13.
To select no columns from a table, use an empty array for the list of
columns. This usage works in the from() method too, but typically you
want some columns from the primary table in your queries, whereas you
might want no columns from a joined table.
$select = $db->select()
->from(array('p' => 'products'),
array('product_id', 'product_name'))
->join(array('l' => 'line_items'),
'p.product_id = l.product_id',
array() ); // empty list of columns
you can specify column name for other table and main table like below
$table->select()
->setIntegrityCheck(false) //required for multi-table join
->from('modules',array('modules.*'))
->joinInner(
'basket_modules',
'modules.id = basket_modules.id',array('basket_modules.id'))
->joinInner(
'baskets',
'baskets.id = basket_modules.basket_id',array('baskets.id'))
->where('baskets.id = ?', $this->id);
so sql will be like
SELECT modules.*, basket_modules.id, baskets.id
FROM modules
INNER JOIN basket_modules ON modules.id = basket_modules.id
INNER JOIN baskets ON baskets.id = basket_modules.basket_id
WHERE (baskets.id = '3')
$table->select()
->setIntegrityCheck(false) //required for multi-table join
->from('modules')
->joinInner(
'basket_modules',
'modules.id = basket_modules.id',array(''))
->joinInner(
'baskets',
'baskets.id = basket_modules.basket_id',array(''))
->where('baskets.id = ?', $this->id);
Give a empty array as the third parameter of join otherwise it will select all the field from the table joined.If you want some fields then specify field names in the array while joining.

Zend Framework: How Do I 'auto' generate a SQL query correctly

I want to generate the following SQL:
SELECT `rc`.*, `c`.`name` FROM `RunConfigurations` AS `rc` INNER JOIN `Clients` AS `c` ON rc.client_id = c.id WHERE (rc.client_id = ?) ORDER BY `rc`.`config_name` ASC
However I am getting:
SELECT `rc`.*, `c`.* FROM `RunConfigurations` AS `rc` INNER JOIN `Clients` AS `c` ON rc.client_id = c.id WHERE (rc.client_id = ?) ORDER BY `rc`.`config_name` ASC
The difference is I want c.name, not c.*
Using the following ZF PHP code:
public function fetchConfigurations($clientId = null, $order = 'rc.config_name ASC')
{
$db = $this->getDb();
$stmt = $db->select()
->from(array('rc' => 'RunConfigurations','c.name'))
->join(array('c' => 'Clients'),'rc.client_id = c.id')
->order($order);
if(is_numeric($clientId))
{
$stmt->where('rc.client_id = ?')
->bind(array($clientId));
}
$results = $db->fetchAll($stmt);
if(sizeof($results) > 0)
{
$configs = array();
foreach($results as $row)
{
$configs[] = $this->createRunConfigurationFromRow($row);
}
return $configs;
}
else
{
die($stmt->__toString());
return null;
}
}
This is aggravating and I feel like I am missing something at either:
->from(array('rc' => 'RunConfigurations','c.name'))
or
->join(array('c' => 'Clients'),'rc.client_id = c.id')
and the ZF examples are not shedding any light on this.
You are so close! join() actually has a 3rd parameter in which you can supply the column names just like the 2nd parameter from from().
This would mean that ->join(array('c' => 'Clients'),'rc.client_id = c.id',array('name')) should generate the SQL you are looking for.
-- Quote from the Zend Framework manual:
The third argument to join() is an array of column names, like that used in the from() method. It defaults to "*", supports correlation names, expressions, and Zend_Db_Expr in the same way as the array of column names in the from() method.

Lots and lots of joins in a Zend Query, hopefully just a slight tweak

Apologies for all this code, anyhow Im re-working a query into the Zend query way of working, this is what I have so far:
$db = Zend_Registry::get ( "db" );
$stmt = $db->query('
SELECT recipe_pictures.picture_id, recipe_pictures.picture_filename, course.course_name, cuisines.name, recipes.id, recipes.Title, recipes.Method, recipes.author, recipes.SmallDesc, recipes.user_id, recipes.cuisine, recipes.course, recipes.Created_at, recipes.vegetarian, recipes.Acknowledgements, recipes.Time, recipes.Amount, recipes.view_count, recipes.recent_ips, guardian_writers.G_item, guardian_writers.G_type
FROM recipes
LEFT JOIN course ON recipes.course = course.course_id
LEFT JOIN recipe_pictures ON recipes.id = recipe_pictures.recipe_id
LEFT JOIN cuisines ON recipes.cuisine = cuisines.id
LEFT JOIN guardian_writers ON recipes.author = guardian_writers.G_author
WHERE recipes.id = ?', $id);
$stmt->setFetchMode(Zend_Db::FETCH_ASSOC);
$recipes = $stmt->fetchAll();
return $recipes;
That one above works, trying to get the Zend version properly, my effort is below.
$db = Zend_Registry::get ( "db" );
$select = $db->select()
->from(array('r' => 'recipes'))
->join(array('c' => 'course'),
'r.course = c.course_id')
->join(array('rp' => 'recipe_pictures'),
'r.id = rp.recipe_id')
->join(array('cui' => 'cuisines'),
'r.cuisine = cui.id')
->join(array('gw' => 'guardian_writers'),
'r.author = gw.G_author')
->where(' id = ? ', $id);
$recipes = $db->fetchRow($select);
return $recipes;
If anyone can spot an error Id be very grateful, thanks
Use joinLeft instead of join to produce left joins.
To fetch specific columns from a table, rather than all (*) use this:
->from(array('r' => 'recipes'), array('id', 'title', 'method'))
or
->joinLeft(array('rp' => 'recipe_pictures'),
'r.id = rp.recipe_id',
array('picture_id', 'picture_filename')
)
To fetch no columns from a table, pass an empty array as the third parameter.
The join method provides an sql INNER JOIN. If you want to get a LEFT JOIN you should use joinLeft.

Categories