How Do I do Select Statement in _preparecollection in Magento if the table I joined in the Main table has 2 rows with 1 parent ID.
Tables I have now.
Table 1(Main Table)
Table 2(sales_flat_invoice_comment)
My Current Prepare Collection
$collection = Mage::getResourceModel($this->_getCollectionClass());
$collection->getSelect()->join( array('a'=> mgmx_sales_flat_invoice_comment), 'a.parent_id = main_table.entity_id', array('a.comment'));
$this->setCollection($collection);
return parent::_prepareCollection();
This query, in echoed will be like this
SELECT main_table.*, a.comment
FROM mgmx_sales_flat_invoice_grid AS main_table
INNER JOIN mgmx_sales_flat_invoice_comment AS a
ON a.parent_id = main_table.entity_id
But it will return an error if this query finds more than 1 row in table 2.
What I want is for something like the one below
With | as a delimiter.
How Can I achieved this in the _prepareCollection of Magento.
you have to group by the entity_id and then use group_concat to create your comment column. You can define a separator in the group by.
The concatenated column has a limit in length. So depending on the length of your single comments and the number of comments it might happen that you do not get all of them in the result.
I hope this helps with solving your problem.
To get the group_concat loading in the zend framework you can define it using the Zend_Db_Expr object
Something like
$collection->getSelect()->join(
array('a'=> new Zend_Db_Expr('GROUP_CONCAT(mgmx_sales_flat_invoice_comment)')),
'a.parent_id = main_table.entity_id',
array('a.comment')
);
Which is handy to know about whenever you need to do custom database functions inside the zend framework.
Related
Below is my pure SQL query.
SELECT SUM(money) AS total_money, user_id
FROM User
INNER JOIN Person
ON Person.user_id = User.user_id
GROUP BY user_id
How can I convert this pure query into ActiveRecord in Yii framework 2? I could solve the INNER JOIN but don't know how to solve SUM including GROUP BY with Yii 2 ActiveRecord
SELECT part:
use yii\db\Expression;
...
->select([new Expression('SUM(money) as total_money'), 'user_id'])
GROUP BY part:
->groupBy('user_id')
Docs for select() and groupBy() can be found in Query Builder section.
yii\db\Expression is used to prevent quoting.
You can not use sum() method here because it's aggregation method and returns a number, while in your case you use it with other column to return a set of records.
The whole query will look like this:
$personTable = Person::tableName();
$userTable = User::tableName();
$users = User::find()
->select([new Expression('SUM(money) as total_money'), 'user_id'])
->innerJoin($personTable, "$personTable.user_id = $userTable.user_id")
->groupBy('user_id')
->all()
A couple more things to mention:
It's better to use tableName() method to get actual table name instead of writing it manually. In this case if you decide to change table name, you only need to change it in one place.
It's better to replace join part with relation.
$atsum =Atttransactions::find()->select([new \yii\db\Expression('SUM(attt_for_receive) as for_receive')])
->addselect([new \yii\db\Expression('SUM(attt_received) as received')])
->where(['attt_attc_id'=>$modelTran->attt_attc_id])
->asArray()->one();
i have multiple table that join together and i need one query and get all references too ! is that possible in yii2??
get them in hierarchy array ??
How ???
Is it possible to do not use join???
thanks for your help!!!!
If you created the model classes for each table using Gii and selected to create the relations in the generated models, you can do something like the following.
1) In your Countries model just change the method that declares the relationship with Airports like this:
public function getAirports() {
return $this->hasMany(Airports::className(), ['country_id' => 'id'])->with('airlines');
}
2) When you do the query for the countries and you need to have the related airports, airlines and flightbooked do it like this:
$countries = Countries::find()
->where('something = something_else')
->with('airports')
->with('flightbooked')
->all();
This way you will get all the related models populated with way less queries to the database than using lazy-loading.
I just wanted to give a small suggestion:
As you are maintaining the relations in the tables and if you have generated your code using Gii, then that will generate the joins for you. You can then access any column of any table easily.
But I think UNION may not be an alternative to JOIN.
Maybe u can use union all for this. with this operator, you can concatenate the result sets from multiple queries together, preserving all of the rows from each. Note that a UNION operator (without the ALL keyword) will eliminate any "duplicate" rows which exist in the resultset. The UNION ALL operator preserves all of the rows from each query (and will likely perform better since it doesn't have the overhead of performing the duplicate check and removal operation).
The number of columns and data type of each column must match in each of the queries. If one of the queries has more columns than the other, we sometimes include dummy expressions in the other query to make the columns and datatypes "match". Often, it's helpful to include an expression (an extra column) in the SELECT list of each query that returns a literal, to reveal which of the queries was the "source" of the row.
SELECT 'col1' AS source, col23, col343, col33, d FROM table1 WHERE ...
UNION ALL
SELECT 'col2', t2.fee, table2.fi, table2.fo, 'fum' FROM table2 JOIN table3 ON ...
UNION ALL
SELECT 'col3', '1', '2', buckle, my_shoe FROM table4
You can wrap a query like this in a set of parenthesis, and use it as an inline view (or "derived table", in MySQL lingo), so that you can perform aggregate operations on all of the rows. e.g:
select one.a
, SUM(one.b)
FROM (
SELECT 'q1' AS source, a, b, c, d FROM t1
UNION ALL
SELECT 'q2', t2.fee, t2.fi, t2.fo, 'fum' FROM t2
) one
GROUP BY one.a
ORDER BY one.a
But i think joining tables more suitable. Hope help you
Is it possible to JOIN a subselect with another table in Laravel 5 Query Builder?
I mean - theoretically - something like this:
$sub = DB::table('A')->select(DB::Raw('id, MAX(date)'))->groupBy('id')->get();
$query = DB::table('B')->join($sub, 'B.id', '=', $sub->id)->get();
In my case, in table A I have duplicated rows. I need the ones with max date per id. Then I need to join the result with table B.
As adviced in comments, a workaround follows.
$idArray= DB::table('A')->select(DB::Raw('id, MAX(date)'))->groupBy('id')->lists('id');
$query = DB::table('B')->whereIn('id', $idArray)->get();
But, again, just a workaround.
I have 2 Tables:
region: region_id,name,state_id
state: state_id,name
I want both names in my result, state.name renamed to statename.
So far I got this:
$select = $select->from(array('r' => 'region'))->join(array('s' => 'state'),
'r.state_id = s.state_id',array("statename" =>"r.name"));
which results in following query:
SELECT `r`.*, `r`.`name` AS `statename` FROM `region` AS `r`
INNER JOIN `state` AS `s` ON r.state_id = s.state_id
So i just need to change r.name AS statename to s.name AS statename.
But i cant get it to work. If i change the last part of the select to array("statename" =>"s.name"), i get an error
Select query cannot join with another table
So how can i rename a field in the joining table?
You have to remove the integrity check.
$table = new self();
$select = $table->select()->setIntegrityCheck(false);
$select = $select->from(array('r' => 'region'))->join(array('s' => 'state'),'r.state_id = s.state_id',array("statename" =>"s.name"));
The integrity check is there to make sure your query is not going to use columns from another table, so Zend_Db_Table_Row objects can be updated, saved or deleted. If you remove the integrity, you're telling Zend that you know what you're doing and you want to use columns from another table.
Here's a brief explanation from documentation:
The Zend_Db_Table_Select is primarily used to constrain and validate
so that it may enforce the criteria for a legal SELECT query. However
there may be certain cases where you require the flexibility of the
Zend_Db_Table_Row component and do not require a writable or deletable
row. for this specific user case, it is possible to retrieve a row or
rowset by passing a FALSE value to setIntegrityCheck(). The resulting
row or rowset will be returned as a ‘locked’ row (meaning the save(),
delete() and any field-setting methods will throw an exception).
I have two tables, one that has a foreign key from the other. I want to get all records that don't exist in the foreign table, based on certain criteria.
Here are the tables I have:
item_setting
setting_id
category_id
item
item_id
setting_id
name
expired_dt
Here's the query I'm using now:
SELECT
iset.setting_id
FROM
item_settings iset
LEFT OUTER JOIN
item i ON i.setting_id = iset.setting_id
WHERE
iset.category_id = '5' AND i.setting_id is null
This query works in providing any setting_id's that do not have a record in the item's table within a specific category.
However, now I want to include cases where the expired_dt less than than time() (meaning it's past expired). In otherwords, I would think to add this:
WHERE
iset.category_id = '5' AND (i.setting_id is null OR i.expired_dt < '".time()."')
However, this doesn't work, it returns all the records.
Any suggestions? Maybe I'm completely over complicating this.... I just want to return the setting_id's from the item_settings table, where the expired_dt associated in the item table is expired or if it does not even exist in the item table.
Thank you!
Try moving the timestamp condition into the join clause. Something like
item_settings iset
LEFT OUTER JOIN
item i ON i.setting_id = iset.setting_id and i.expired_dt > time()