Get all current joins to a query in yii2 ActiveQuery - mysql

Is there a way to get all joined table from a query?
For example:
query = Account::find()->joinWith(['gallery'])->joinWith(['articles'])->etc...
Is there any integrated method in yii2 that will return the above joined tables (or an event on which I could hook to get them manually)?

Solution suggested by #Beowulfenator shows only joins with relations (which added with joinWith() method.
To show all joins you need prepare the query like this:
$query = Account::find()
->join('...', '...')
->joinWith(['gallery', 'articles']); // By the way, you can reduce you code like this
$query->prepare();
This will transform yii\db\ActiveQuery to simple yii\db\Query which doesn't have joinWith property but has join property that shows exactly all joins.
You can var_dump and see it:
var_dump($query->join);
exit();
First element stores type of join, second - table name (note that it can be either string or array depending on used relation), third - on condition.

ActiveQuery class has joinWith public property. It's an array that contains information on all joins. It, among other things, contains joined table names.
More info here.

Related

Filter an array passed from query params. NestJS, TypeORM

I’m using NestJS with TypeORM, database is MySQL, and I’d like to filter multiple parameters that can be passed in.
The frontend has a list of products and filters are applied as query params sent to NestJS, filtering works for a single param eg api.example.com?manufacturer=Acer but how would I filter an Array eg api.example.com?manufacturer=Acer,Toshiba,Asus.
I tried quite a few things in TypeORM, currently using the QueryBuilder to build the array with an if statement if the filter exists if so I’m doing something like a where statement.
.andWhere(manufacturer = filterOne, {filterOne: *manufacturers from the query param*})
But yeah just can’t hack something together, tried a couple of things, above is a rough example, did try methods that TypeORM had as an example on filtering arrays but it seemed like it was more for an array of integers only? Regardless, I’m open to any methods that allow for the end result of filtering the example I provided, cheers and thanks again!
You have to use IN to get all data where manufacturer equal the data came from the query, first, you have to convert the query to an array:
var manufacturerParam = filterOne.split(",");
then add it to your query:
.andWhere(manufacturer IN (:filter)", { filter: manufacturerParam })

correctly fetch nested list in SQL

I have a design problem with SQL request:
I need to return data looking like:
listChannels:
-idChannel
name
listItems:
-data
-data
-idChannel
name
listItems:
-data
-data
The solution I have now is to send a first request:
*"SELECT * FROM Channel WHERE idUser = ..."*
and then in the loop fetching the result, I send for each raw another request to feel the nested list:
"SELECT data FROM Item WHERE idChannel = ..."
It's going to kill the app and obviously not the way to go.
I know how to use the join keyword, but it's not exactly what I want as it would return a row for each data of each listChannels with all the information of the channels.
How to solve this common problem in a clean and efficient way ?
The "SQL" way of doing this produces of table with columns idchannel, channelname, and the columns for item.
select c.idchannel, c.channelname, i.data
from channel c join
item i
on c.idchannel = i.idchannel
order by c.idchannel, i.item;
Remember that a SQL query returns a result set in the form of a table. That means that all the rows have the same columns. If you want a list of columns, then you can do an aggregation and put the items in a list:
select c.idchannel, c.channelname, group_concat(i.data) as items
from channel c join
item i
on c.idchannel = i.idchannel
group by c.idchannel, c.channelname;
The above uses MySQL syntax, but most databases support similar functionality.
SQL is made for accessing two-dimensional data tables. (There are more possibilities, but they are very complex and maybe not standardized)
So the best way to solve your problem is to use multiple requests. Please also consider using transactions, if possible.

Yii2: ActiveQuery "with" not working

Circumstances
I have three models/db-tables related with 1:n each: An order has multiple commissions and a commission has multiple commission_positions. Therefore the commission_position has an FK-field containing a commission id. The commission itself has an FK-field containing the id of an order.
Order > Commission > CommissionPositions
Problem
What I need to do now is select all the CommissionPositions having a certain value in the related Order-Model. Obvious solution is to use the Query-Object of CommissionPosition which I extended with a named scope. The named scope looks like this:
class CommissionPositionQuery extends ActiveQuery
{
/**
* Named scope to filter positions of a certain alpha order id
* #param integer $id the alpha order id
* #return \common\models\query\CommissionPositionQuery
*/
public function alphaOrderId($id)
{
//TODO: with not working
$this->with(['commission.order']);
$this->andWhere(['alpha_order_id'=>$id]);
return $this;
}
}
The relation commission is defined on the Commission-Model and working. The second relation order is defined on the commission-model and working as well. The filtered field alpha_order_id is in the Order-Table. Now I execute the query like this:
$filteredPositions = CommissionPosition::find()->alphaOrderId(17)->all();
The scope is called successfully and the where-part is used, but when I check the generated SQL I see no join-statements even though I use the with-method to tell yii to fetch the relation together. The response is 'unknown column alpha_order_id' which makes sense as there is no join to the related tables. This is the generated SQL:
SELECT * FROM `commission_position` WHERE (`alpha_order_id`=17)
What am I missing? Is this a bug of Yii2?
Found the soution myself. The naming changes between Yii1 and Yii2 lead to a little confusion. To prevent others from wasting time here the details:
Yii1
In yii 1 you would join in a relation (exemplary: commission) directly like this:
$query->with = 'commission'
$query->together = true;
Yii2 / difference
When calling the with-method like showed in the question the relation was successfully added to the with-array of the ActiveQuery. However, when executing the query, the join part was missing.
Solution
Seems like the with-method is NOT the way to go. Instead I used the method called joinWith with the following signature:
public function joinWith($with, $eagerLoading = true, $joinType = 'LEFT JOIN')
Now as described in the answer I defined the relation as the first argument ('commission.order') and left the rest as is, because the default values are perfectly fine. Pay attention to the default value of the second parameter. this makes sure the relations are joined in directly!
Voilà...the resulting sql contains the needed joins. One pitfall is to be considered though: Ambigious column namings is of course to be handled by ourselves! Link to the documentation of the method:
http://www.yiiframework.com/doc-2.0/yii-db-activequery.html#joinWith()-detail
If you want a JOIN use:
$this->joinWith(['commission.order']);

How do I separate the results

I have the following query on Doctrine QueryBuilder:
$qb = $this->createQueryBuilder('e')
->select('e.id, e.name, e.body, e.teaser, e.slug, e.dateBegin, e.dateEnd, e.dateTbd, v.name AS v_name')
->innerJoin('e.venue', 'v')
->where('v.name LIKE :TBD')
->orWhere('v.name LIKE :TBA')
->orWhere('e.name LIKE :TBD')
->orWhere('e.name LIKE :TBA')
->orWhere('e.name LIKE \'none\'')
->orWhere('e.name LIKE \'n/a\'')
->orWhere('e.teaser LIKE :TBD')
->orWhere('e.body LIKE :TBD')
->orWhere('e.dateTbd=true')
->orWhere('TIME(e.dateBegin) < :earlyMorning AND TIME(e.dateBegin) > :lateNight')
->setParameter('TBA', '%TBA%')
->setParameter('TBD', '%TBD%')
->setParameter('earlyMorning', '06:00:00')
->setParameter('lateNight', '23:00:00');
How I can separate the results by 'where' clause in this query. I need to display every event with criteria which listed in where clause.
I can't see a way of achieving this easily, especially if we are to assume you're using this to retrieve a standard doctrine entity collection, since additional grouping / properties wouldn't really be something you could pass into these.
If you need to group these simply to display them slightly differently as they're output, say, in your markup, I'd consider adding additional methods into your entity's class to allow you detect which 'type' they are based on similar criteria defined in your query, e.g. using standard string matching functions.
Otherwise your options are going to be filtering the collection (ArrayCollections carry a method for doing that easily) or separating it out into multiple queries, which given your approach, I assume you are trying to avoid.

SQL Alchemy return list of ids

I am using SQL Alchemy and I want to return a list of Document Ids. The Ids are the primary key in the documents table. My current query returns a list of tuples.
userDocs = session.query(Document.idDocument).filter(Document.User_idUser == user.idUser).all()
The reason I want a list of ids is so that I can search another table using in_(userDocs).
So another solution would be to be able to search using tuples. I am currently returning nothing from my second query using userDocs.
Thank you!!
You don't need to do an intermediate query, you can do this all in one shot!
things = session.query(Things) \
.join(Thing.documents) \
.filter(Document.User_idUser==user.idUser)
You just query on the properties of the Document through its relationship() on the intended entity.