codeigniter Database class JOIN USING - php

how can i use
left JOIN Table2 using(table.id) ?
Example of my CODE
$this->db->select('visits.*,patients.name,workers.dr_name,time(visits.time)');
$this->db->from('visits');
//The next join = LEFT JOIN workers ON visits.worker_id=workers.worker_id
$this->db->join('workers','visits.worker_id=workers.worker_id','left');//WORKING
//The next join = JOIN `patients` ON patient_id --> i want it JOIN patients USING(patient_id)
$this->db->join('patients','patient_id','USING');//NOT WORKING
i searched every were, yet couldnt find a solution, and so i opened and tried to edit JOIN function in db_active_rec.php
/system/database/DB_active_rec.php
and found the join function
public function join($table, $cond, $type = '')
{
if ($type != '')
{
$type = strtoupper(trim($type));
if ( ! in_array($type, array('LEFT', 'RIGHT', 'OUTER', 'INNER', 'LEFT OUTER', 'RIGHT OUTER')))
{
$type = '';
}
else
{
$type .= ' ';
}
}
// Extract any aliases that might exist. We use this information
// in the _protect_identifiers to know whether to add a table prefix
$this->_track_aliases($table);
// Strip apart the condition and protect the identifiers
if (preg_match('/([\w\.]+)([\W\s]+)(.+)/', $cond, $match))
{
$match[1] = $this->_protect_identifiers($match[1]);
$match[3] = $this->_protect_identifiers($match[3]);
$cond = $match[1].$match[2].$match[3];
}
// Assemble the JOIN statement
$join = $type.'JOIN '.$this->_protect_identifiers($table, TRUE, NULL, FALSE).' ON '.$cond;
$this->ar_join[] = $join;
if ($this->ar_caching === TRUE)
{
$this->ar_cache_join[] = $join;
$this->ar_cache_exists[] = 'join';
}
return $this;
}
tried to edit the part under "// Assemble the JOIN statement" and put ifcondition to detect USING and then adjust the query accordingly but failed.. epic fail
can any one help ? how can i edit this function so that it would use USING in Join query ?

From the manual:
$this->db->join();
Permits you to write the JOIN portion of your query:
$this->db->select('*');
$this->db->from('blogs');
$this->db->join('comments', 'comments.id = blogs.id');
$query = $this->db->get();
// Produces:
// SELECT * FROM blogs
// JOIN comments ON comments.id = blogs.id
Multiple function calls can be made if you need several joins in one query.
If you need a specific type of JOIN you can specify it via the third parameter of the function. Options are: left, right, outer, inner, left outer, and right outer.
$this->db->join('comments', 'comments.id = blogs.id', 'left');
// Produces: LEFT JOIN comments ON comments.id = blogs.id

Related

Applying multiple conditions in zf2 left join

I have a zf2 left join query like this
$select->join(
'contractor_jobs',
'contractor_jobs.contractor_id = contractor_info.contractor_id',
array('job_trade_id'),
$select::JOIN_LEFT
);
I want to apply another condition as 'contractor_jobs.job_trade_id = $variableName' during joining. please help me.
You can use expression:
$join = new \Zend\Db\Sql\Expression('contractor_jobs.contractor_id = contractor_info.contractor_id AND
contractor_jobs.job_trade_id = '.$variableName.' ');
$select->join(
'contractor_jobs',
$join,
array('job_trade_id'),
$select::JOIN_LEFT
);

Second counting query for pagination

I have a couple of pretty complex queries, and for each of them I have to write a second query counting results. So for example, in the model:
$dql = "SELECT u FROM AcmeBundle:Users u LEFT JOIN AcmeBundle:Products p WITH u.id = p.id";
I would have to create a duplicate query like this:
$countingQuery = "SELECT COUNT(u.id) FROM AcmeBundle:Users u LEFT JOIN AcmeBundle:Products p WITH u.id = p.id";
The main problem with that is that with every change in the first query, I would have to change the second either.
So I came up with another idea:
$countingSelect = "SELECT COUNT(u.id)";
$noncountingSelect = "SELECT u";
$dql = " FROM AcmeBundle:Users u LEFT JOIN AcmeBundle:Products p WITH u.id = p.id";
return $this->getEntityManager()->createQuery($noncountingSelect . $dql)
->setHint('knp_paginator.count', $this->getEntityManager()->createQuery($countingSelect . $dql)->getSingleScalarResult());
It works of course, but the solution seems quite ugly with larger selects.
How can I solve this problem?
I believe the Doctrine\ORM\Tools\Pagination\Paginator will do what you're looking for, without the additional complexity.
$paginator = new Paginator($dql);
$paginator
->getQuery()
->setFirstResult($pageSize * ($currentPage - 1)) // set the offset
->setMaxResults($pageSize); // set the limit
$totalItems = count($paginator);
$pagesCount = ceil($totalItems / $paginator->getMaxResults());
Code yanked from: http://showmethecode.es/php/doctrine2/doctrine2-paginator/
You can create a customer repository as explained in the docs and add your query to that with a minor edit like..
use Doctrine\ORM\EntityRepository;
class ProductRepository extends EntityRepository
{
public function findProducts()
{
return $this->findProductsOrCountProducts();
}
public function findCountProducts()
{
return $this->findProductsOrCountProducts(true);
}
private function findProductsOrCountProducts($count = false)
{
$queryBuilder = $this->createQueryBuilder('u');
if ($count) {
$queryBuilder->select('COUNT(u.id)');
}
$query = $queryBuilder
->leftJoin('AcmeBundle:Products', 'p', 'WITH', 'u.id = p.id')
->getQuery()
;
if ($count) {
return $query->getSingleScalarResult();
} else {
return $query->getResult();
}
}
}
Then you can call your method using...
$repository = $this->getDoctrine()
->getRepository('AcmeBundle:Users');
// for products
$products = $repository->findProducts();
// for count
$countProducts = $repository->findCountProducts();
Note:
I know it's not best practice to just say look at the docs for the customer repository bit s here' the YAML mapping...
# src/Acme/StoreBundle/Resources/config/doctrine/Product.orm.yml
Acme\StoreBundle\Entity\Product:
type: entity
repositoryClass: Acme\StoreBundle\Entity\ProductRepository
# ...

Symfony createNativeQuery, add count()

I have a query in a repository like :
$rsm = new ResultSetMapping;
$rsm->addEntityResult('\My\ProjectBundle\Entity\News', 't');
$rsm->addFieldResult('t', 'id', 'id');
$rsm->addMetaResult('t', 'account_id', 'account_id');
$qb = $this->_em->createNativeQuery(
'SELECT t.*
FROM news as t
LEFT JOIN
LEFT JOIN
WHERE
CONDITIONS CONDITIONS
',
$rsm
);
return $qb->getResult();
I simplified the above query which is used to retrieve the news that meet specific conditions.
I need to add a count() function to this query.
I have an other ManyToOne entity-relationship between Comment and News.
How to modify the query to get the comments number a given news has ?
I'm trying to add a left join to comment and add Count() in the select but I always get errors. How could I resolve this problem ?
Raw SQL with Doctrine is easier like this :
$em = $this->getDoctrine()->getManager()->getConnection();
$query = "
SELECT t.*
FROM news as t
LEFT JOIN
LEFT JOIN
WHERE
CONDITIONS CONDITIONS
";
$stmt = $em->prepare($query);
$stmt->execute();
$result = $stmt->fetchAll();

Delete rows with Laravel query builder and LEFT JOIN

How to delete rows from multiple tables in one query (with left join).
The query:
DELETE `deadline`, `job` FROM `deadline` LEFT JOIN `job` ....
So, I try it like this:
DB::table('deadline', 'job')
->leftJoin('job', 'deadline.id', '=', 'job.deadline_id')
->where('deadline.id', $id)
->delete();
Seems that Laravel doesn't support delete from multiple tables with left join.
Is there a supported way or workaround?
It seems that my way is not possible. So, I did it like this.
$q = 'DELETE deadline, job FROM deadline LEFT JOIN job ...where deadline.id = ?';
$status = \DB::delete($q, array($id));
Documentation: http://laravel.com/docs/database#running-queries
DB::table(DB::raw('deadline, job')) might work. If it doesn't, you'll have to write the SQL manually and call it via DB::statement().
To make laravel allow a join in a delete is simple - you just need to change the compileDelete function in Illuminate\Database\Query\Grammars\Grammar to this:
public function compileDelete(Builder $query)
{
$table = $this->wrapTable($query->from);
$components = implode(' ', array(
is_array($query->joins) ? $this->compileJoins($query, $query->joins) : '',
is_array($query->wheres) ? $this->compileWheres($query, $query->wheres) : '',
is_array($query->limit) ? $this->compilelimit($query, $query->limit) : '',
is_array($query->offset) ? $this->compileOffset($query, $query->offset) : ''
));
return trim("delete $table from $table ".$components);
}
Then ->delete() will work the way you expect it to. I've already added this as a pull request to the laravel framework repo, so hopefully this might be merged into the next version - just have to see.
$query = 'DELETE courses,course_contents FROM courses
INNER JOIN course_contents ON course_contents.course_id = courses.id
WHERE courses.id = ?';
\DB::delete($query, array($id));

Symfony2 + doctrine's query builder - where != 1

I have a function that creates a query to my db, like this:
public function getList($u, $t, $ls, $lf) {
return $this->getEntityManager()
->createQuery('
SELECT
o,
u,
g,
r,
t,
p
FROM GameShelfUsersBundle:Own o
LEFT JOIN o.user u
LEFT JOIN o.game g
LEFT JOIN o.rate r
LEFT JOIN o.typo t
LEFT JOIN o.platforms p
WHERE u.id = :user
AND o.typo = :type
ORDER BY o.updated DESC
')
->setParameters(array(
'user' => $u,
'type' => $t
))
->setMaxResults($lf)
->setFirstResult($ls)
->getResult();
}
My problem is, how to set :type to be not in? I mean, I wanted to use it like this:
$type = '!= 1'
...
AND o.typo :type
...
'type' => $type
But it didn't worked at all. Using $type = -1 doesn't help either. Is there any way, other than creating if/else statement and duplicating query?
Why don't you use a query builder??
In that way you can easily customize your query, depending on some condition.
This is an example:
$q = $this
->createQueryBuilder('foo')
->select('foo')
->leftJoin('foo.bar', 'foobar')
->leftJoin('foobar.bar', 'foobarbar')
;
if($myVar > 0)
{
$q->where('foobarbar.var = :myVar');
}
else
{
$q->where('foobarbar.var = :staticValue');
}
[...]
Remember to call return $q->getResult(); at the end

Categories