how to combine queries yii2 - activerecord

I have a query with 2 tables. I want to combine these two queries into one query. how do?
public function actionGroup()
{
$query1 = (new \yii\db\Query())
->select(['lao',new \yii\db\Expression('COUNT(lao)'),'nama_ptgs', new \yii\db\Expression('SUM(outstanding)')])
->from('debitur')
->groupBy('lao')
->all();
$query2 = (new \yii\db\Query())
->select(['lao', new \yii\db\Expression('SUM(tgt_pergeseran)')])
->from('resume')
->groupBy('lao')
->all();
return $this->render('outstanding', [
'query1' => $query1,
'query2' => $query2,
]);
}
example sql
SELECT debitur.lao, debitur.Outstanding, debitur.jumlah, resume.Target FROM ( SELECT lao, SUM(outstanding) as Outstanding, COUNT(lao) as jumlah FROM debitur GROUP BY lao )debitur INNER JOIN ( SELECT lao, SUM(tgt_pergeseran) as Target FROM resume GROUP BY lao ) resume ON debitur.lao = resume.lao
error undefined index
print($query);
result

The raw query you provided does not have any where() condition for the main query
SELECT debitur.lao, debitur.Outstanding, debitur.jumlah, resume.Target
FROM
(SELECT lao, SUM(outstanding) as Outstanding, COUNT(lao) as jumlah FROM debitur GROUP BY lao) debitur
INNER JOIN
(SELECT lao, SUM(tgt_pergeseran) as Target FROM resume GROUP BY lao) resume
ON debitur.lao = resume.lao
If that is the complete and correct query that show you the right results in the phpmyadmin widow, you need to use the sub query like below
$subQueryFrom = new \yii\db\Query();
$subQueryFrom->select(['lao', new \yii\db\Expression('SUM(outstanding) as Outstanding, COUNT(lao) as jumlah')])
->from('debitur')
->groupBy('lao');
$subQueryJoin = new \yii\db\Query();
$subQueryJoin->select(['lao', new \yii\db\Expression('SUM(tgt_pergeseran) as Target')])
->from('resume')
->groupBy('lao');
$query = new \yii\db\Query();
$results = $query->select(['debitur.lao', 'debitur.Outstanding', 'debitur.jumlah', 'resume.Target'])
->from(['debitur' => $subQueryFrom])
->innerJoin(['resume' => $subQueryJoin], 'debitur.lao = resume.lao')
->all();
You can now use the $result in your view which holds the records against your query.
return $this->render('outstanding', [
'results' => $results,
]);

In order to combine the results from 2 queries from 2 different tables you can use the Union Operator. From the link there are necessary conditions though:
Each SELECT statement within UNION must have the same number of
columns
The columns must also have similar data types
The columns in each SELECT statement must also be in the same order
In order for this to work for you, you need to alter your queries as follows:
$query1 = (new \yii\db\Query())
->select(['lao',
new \yii\db\Expression('COUNT(lao) as count_column'),
'nama_ptgs',
new \yii\db\Expression('SUM(outstanding) as sum_column'),
new \yii\db\Expression('NULL as tgt_sum')])
->from('debitur')
->groupBy('lao');
$query2 = (new \yii\db\Query())
->select(['lao',
new \yii\db\Expression('NULL as count_column'),
new \yii\db\Expression('NULL as nama_ptgs'),
new \yii\db\Expression('NULL as sum_column'),
new \yii\db\Expression('SUM(tgt_pergeseran) as tgt_sum'),
])->from('resume')
->groupBy('lao');
In short if your first table contains columns a and b, and your second contains columns a and c. Then what you need to do is select(['a','b','NULL as c']) from the first and select(['a','NULL as b','c']) from the second so that you can combine the two results
Then the combined query is simply:
$combinedQuery = $query1->union($query2);

Related

Doctrine Many-To-Many bulk insert

I need to do a bulk insert of thousands of records (5k up to 20k).
The scenario is User<->n:m<->Group. The list of users is obtained by a complex query with many joins.
I have access to the QueryBuilder that generates the list.
The simpliest approach to add the users to the group is
$users = $this->repository->findRecipientsByCriteria($group->getCriteria());
foreach ($users as $user){
$group->addUser($user);
}
But for the number of users involved i don't think it's a good idea (in term of performances).
I can't even iterate results because of the fetch join relations.
I would like to inject the QueryBuilder Dql (or Sql) to the INSERT statement?
I mean something like:
$qb = $this->repository->getRecipientsByCriteriaQueryBuilder($group->getCriteria());
$qb->select("'".$group->getId()."' AS gruppo_id, U.id AS utente_id");
$d = $qb->getQuery()->getSQL();
$q = $this->entityManager->createNativeQuery('INSERT INTO `msg_gruppo_utente` (`gruppo_id`, `utente_id`) '.$d, new ResultSetMapping());
$q->execute();
But this results in
INSERT INTO `msg_gruppo_utente` (`gruppo_id`, `utente_id`) SELECT '64f105a3-a6ab-460a-8378-84b0c3258601' AS sclr_0, s0_.id AS id_1 FROM security_utente s0_ INNER JOIN security_utente_cliente s1_ ON s0_.id = s1_.utente_id INNER JOIN api_cliente a2_ ON s1_.cliente_id = a2_.id INNER JOIN api_indirizzo_cliente a3_ ON a2_.id = a3_.cliente_id INNER JOIN api_contratto a4_ ON a2_.id = a4_.cliente_id WHERE s1_.verificato = ? AND a3_.city = ?
Where parameters are not set, while i thought thatthe parameters should have been be set in getRecipientsByCriteriaQueryBuilder
Due to doctrine native SQL resctrictions
If you want to execute DELETE, UPDATE or INSERT statements the Native
SQL API cannot be used and will probably throw errors. Use
EntityManager#getConnection() to access the native database connection
and call the executeUpdate() method for these queries.
I've used this solution (executeUpdate is deprecated in favor of executeStatement)
$usersQueryBuilder = $this->repository->getRecipientsByCriteriaQueryBuilder($group->getCriteria());
$usersQueryBuilder->select("'".$group->getId()."' AS gruppo_id, U.id AS utente_id");
$parameters = $usersQueryBuilder->getParameters();
$p = [];
/** #var Parameter $parameter */
foreach ($parameters as $parameter){
$p[] = $parameter->getValue();
}
$conn = $this->entityManager->getConnection();
$conn->executeStatement('INSERT INTO `msg_gruppo_utente` (`gruppo_id`, `utente_id`) '.
$usersQueryBuilder->getQuery()->getSQL(), $p);

How to make and condition with or in laravel query

My query is as below
SELECT * FROM `user_register`
INNER JOIN `locationdetail` on `locationdetail`.`userid` = `user_register`.`id`
INNER JOIN `lifestyle` on `lifestyle`.`userid` = `user_register`.`id`
WHERE `lifestyle`.`drink` in (2) and
( `locationdetail`.`state_id` in (4121) or `locationdetail`.`country_id` in (38))
In this query how to make bracket inner query in laravel model
Sorry there got distracted
$drinks = [1];
$state_ids = [1,2]
$country_ids = [1,2,3]
$someModel
->join() // enter your joins here
->whereIn('lifestyle.drink', $drinks)
->where(function( $q1 ) use ($state_ids, $country_ids) {
// insert the whereOr queries here against the $q1 using the data in `use` params
})
->get();
To check your query there is a toSql() function you can use in laravel too.

Symfony2 subquery within Doctrine entity manager

I need to perform this query:
SELECT * FROM (SELECT * FROM product WHERE car = 'large' ORDER BY onSale DESC) AS product_ordered GROUP BY type
In Symfony2 using the entity manager.
My basic query builder would be :
$query = $em->getRepository('AutomotiveBundle:Car')
->createQueryBuilder('p')
->where('pr.car = ?1')
->andWhere('pr.status = 1')
->orderBy('pr.onSale', 'DESC')
->setParameter(1, $product->getName())
->groupBy('p.type')
->getQuery();
But I cannot work out how to add in a subquery to this.
Ive tried making a separate query and joining it like:
->andWhere($query->expr()->in('pr.car = ?1',$query2->getQuery()));
But I get:
Call to undefined method Doctrine\ORM\Query::expr()
One trick is to build two queries and then use getDQL() to feed the first query into the second query.
For example, this query returns a distinct list of game ids:
$qbGameId = $em->createQueryBuilder();
$qbGameId->addSelect('distinct gameGameId.id');
$qbGameId->from('ZaysoCoreBundle:Event','gameGameId');
$qbGameId->leftJoin('gameGameId.teams','gameTeamGameId');
if ($date1) $qbGameId->andWhere($qbGameId->expr()->gte('gameGameId.date',$date1));
if ($date2) $qbGameId->andWhere($qbGameId->expr()->lte('gameGameId.date',$date2));
Now use the dql to get additional information about the games themselves:
$qbGames = $em->createQueryBuilder();
$qbGames->addSelect('game');
$qbGames->addSelect('gameTeam');
$qbGames->addSelect('team');
$qbGames->addSelect('field');
$qbGames->addSelect('gamePerson');
$qbGames->addSelect('person');
$qbGames->from('ZaysoCoreBundle:Event','game');
$qbGames->leftJoin('game.teams', 'gameTeam');
$qbGames->leftJoin('game.persons', 'gamePerson');
$qbGames->leftJoin('game.field', 'field');
$qbGames->leftJoin('gameTeam.team', 'team');
$qbGames->leftJoin('gamePerson.person', 'person');
// Here is where we feed in the dql
$qbGames->andWhere($qbGames->expr()->in('game.id',$qbGameId->getDQL()));
Kind of a long example but i didn't want to edit out stuff and maybe break it.
You can use DBAL for performing any sql query.
$conn = $this->get('database_connection');//create a connection with your DB
$sql="SELECT * FROM (SELECT * FROM product WHERE car =? ORDER BY onSale DESC) AS product_ordered GROUP BY type"; //Your sql Query
$stmt = $conn->prepare($sql); // Prepare your sql
$stmt->bindValue(1, 'large'); // bind your values ,if you have to bind another value, you need to write $stmt->bindValue(2, 'anothervalue'); but your order is important so on..
$stmt->execute(); //execute your sql
$result=$stmt->fetchAll(); // fetch your result
happy coding

Doctrine 2.0 native query without mapping

I am writing a tiny little migration script and i am only trying to update one attribute of one element.
The Result i need has no Representation in the local Environment, so what i would need is a very simple SQL (here it is Oracle) handler that i can iterate over and get an array returned.
Is that possible with doctrine?
i.e. i would want to do this:
$query = "SELECT t2.status FROM t2 LEFT JOIN t1 ON t1.id = t2.foreinkey";
$iterator = $connection->execute($query)->iterate();
foreach ($iterator as $array) {
// do something with an associative array
}
UPDATE / SOLUTION:
With the Hint from Corbin i came up with this Solution which works pretty fine:
$query = "SELECT t2.status FROM t2 LEFT JOIN t1 ON t1.id = t2.foreinkey";
$iterator = $connection->query($query);
while (is_object($iterator) AND ($array = $iterator->fetch()) !== FALSE) {
// do something with an associative array
}
https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/native-sql.html#native-sql
If you want to do any mapping.
Another option would be to get the connection object from EntityManager::getConnection and operate on it.
It returns a Doctrine\DBAL\Connection which you should be able to work with. It has the typical fetchColumn fetchArray fetchAssoc so on.

Codeigniter: Select from multiple tables

How can I select rows from two or more tables?
I'm setting default fields for a form, and I need values from two tables...
My current code reads:
$this->CI->db->select('*');
$this->CI->db->from('user_profiles');
$this->CI->db->where('user_id' , $id);
$user = $this->CI->db->get();
$user = $user->row_array();
$this->CI->validation->set_default_value($user);
The example in the User Guide should explain this:
$this->db->select('*'); // <-- There is never any reason to write this line!
$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
See the whole thing under Active Record page in the User Guide.
Just add the other table to the "->from()" method. Something like:
$this->db->select('t1.field, t2.field2')
->from('table1 AS t1, table2 AS t2')
->where('t1.id = t2.table1_id')
->where('t1.user_id', $user_id);
I think the question was not so much about joins as how to display values from two different tables - the User Guide doesn't seem to explain this.
Here's my take:
$this->db->select('u.*, c.company, r.description');
$this->db->from('users u, company c, roles r');
$this->db->where('c.id = u.id_company');
$this->db->where('r.permissions = u.permissions');
$query = $this->db->get();
I think the syntax is incorrect.
You need to select one record. I have two tables, and I have an id from one table transfer by parameter, and the relation of both tables.
Try this
$this->db->select('*')
->from('student')
->where('student.roll_no',$id)
->join('student_details','student_details.roll_no = student.roll_no')
->join('course_details','course_details.roll_no = student.roll_no');
$query = $this->db->get();
return $query->row_array();
$SqlInfo="select a.name, b.data fromtable1 a, table2 b where a.id=b.a_id";
$query = $this->db->query($SqlInfo);
try this way, you can add a third table named as c and add an 'and' command to the sql command.
// Select From Table 1 All Fields, and From Table 2 one Field or more ....
$this->db->select('table1.*, table2.name');
$this->db->from('table1, table2');
$this->db->where('table2.category_id = table1.id');
$this->db->where('table2.lang_id',$id); // your where with variable
$query = $this->db->get();
return $query->result();

Resources