Zend Select group by Field - php

I have a query as below:
select status, count(id) as units from myTable group by status
I have a Zend_Db_Table object at my displosal for the table in use, i am trying the below mentioned snippet to create the query above:
$objTable= new Application_Model_DbTable_MyTable();
$select = $objTable -> select(Zend_Db_Table::SELECT_WITH_FROM_PART)
-> setIntegrityCheck(false); // i am also using joins to create the query, but this is not of concern
$select -> columns(array(
'status' => new Zend_Db_Expr('DISTINCT(STATUS)'),
'units' => new Zend_Db_Expr('COUNT(id)')
));
$select -> group('status');
the query created from the above snippet is as follows:
select myTable.*, DISTINCT(STATUS) as status, COUNT(id) as units from myTable group by status
I want to remove the myTable.* from the query generated.

$select = $db ->select()
->distinct()
->from('myTable',array('status', 'COUNT(id) as units'))
->group('status');

Try this instead.
$select = new Zend_Db_Select;
$select->from(
# table
array(
't' => 'myTable'
),
# columns
array(
'status' => 'DISTINCT(STATUS)',
'units' => 'COUNT(id)',
));
->group('status');
The problem is Zend_Db_Select will automatically added table.* to your query if there's no column specified in ->from( clause

Related

Yii 1 - Ordering by relation field not working

I know its a common question but I get a specific error about a not joined table.
My main Model (Group) has this relation (1:1):
return array(
'groupType'=>array(self::BELONGS_TO, 'GroupType', 'groupTypeId','order'=>'name ASC');
As you can see, I've tried to put an order attributes thats is not working.
As you can immagine, my other module, GroupType, has an attribute called 'name'.
In the grid view, the relation model is printed well simply using the name of relation:
array(
'name'=>'groupType',
'value'=>'$data->groupType->name'
),
Autoload is working fine in GridView.
Unfortunally the column is not sortable. So I put a CSort parameter to DataProvider provided in the Search Method as below:
$sort = new CSort();
$sort->defaultOrder = 'id asc';
$sort->attributes = array(
'groupType'=>array(
'asc'=>'groupType.name asc',
'desc'=>'groupType.name desc'
),
'description'=>array(
'asc'=>'t.description asc',
'desc'=>'t.description desc'
),
'name'=>array(
'asc'=>'t.name asc',
'desc'=>'t.name desc'
),
'*');
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
'sort'=>$sort
));
Ordering by description and name (attribute of Group) works fine. When I tried to order by groupType, i get this simply error:
SQL: SQLSTATE[42S22]: Column not found: 1054 Unknown column 'groupType.id' in 'order clause'. The SQL statement executed was: SELECT * FROM `cprol_groups` `t` ORDER BY groupType.idname asc LIMIT 20
As you can see, framework is not joining my related table. And in this case, what Alias I have to use due to same-property name?
Thanks you for any advice!
I've resolved forcing the join.
In the criteria, I have to force join:
$criteria->join = 'join '.GroupType::model()->tableName().' gt on gt.id = t.groupTypeId';
or using the ->with statement:
$criteria->with = 'groupType';
removing the default order in relation and adding an alias:
return array('groupType'=>array(self::BELONGS_TO, 'GroupType', 'groupTypeId','alias'=>'gt'));
so you can order by relation field:
$sort = new CSort();
$sort->defaultOrder = 'gt.name asc';
$sort->attributes = array(
'groupTypeId'=>array(
'asc'=>'gt.name asc',
'desc'=>'gt.name desc'
),

subquery in andFilterWhere in yii2

I have to execute this query
select count(id) as numberofcompanies, sum(offered_value) as total_offered_value from campaign_comapany
where ( campaign_id in (select id from campaing where user_id = current_user ) or campaing_company.sp_user_id = current_user)
and campaign_company.status = '3'
And I wrote the query like this in yii2-
$query->select(['count(id) as numberofcompanies','sum(offered_value) as total_offered_value'])
->from('campaign_company')
->andFilterWhere(['or',['in','campaign_id',(new yii\db\Query())->select(['id'])->from('campaign')->where(['=','user_id',Yii::$app->user->id])],['=','campaign_company.sp_user_id',Yii::$app->user->id]])
->andWhere(['=','status','3'])
->one();
But it gives me error with unknow column campaign_company.user_id
but working if I just use where like following-
$query->select(['count(id) as numberofcompanies','sum(offered_value) as total_offered_value'])
->from('campaign_company')
->where(['in','campaign_id',(new yii\db\Query())->select(['id'])->from('campaign')->where(['=','user_id',Yii::$app->user->id])])
->andWhere(['=','status','3'])
->one();
What should I do to get the result mentioned sql query, I don't want to hit database server two time, thanks in advance
Use join:
$query->select(['count(id) as numberofcompanies','sum(offered_value) as total_offered_value'])
->from('campaign_company')
->innerJoin('campaign','`campaign`.`id` = `campaign_company`.`campaign_id`')
->where([
['=','campaign.user_id',Yii::$app->user->id])],
['=','campaign.campaign_company.sp_user_id',Yii::$app->user->id],
['=','campaign_company.status','3']
]
->one();
As is it is difficult to follow your logic. To simplify your code and your query, add the first condition as plain sql. Also since the second condition is required, you can swap the positions as follows:
$query
->select(['count(id) as numberofcompanies','sum(offered_value) as total_offered_value'])
->from('campaign_company')
->where(['status' => '3'])
->andWhere(['
campaign_id in (select id from campaign where user_id = :current_user )
or campaign_company.sp_user_id = :current_user1',
[':current_user' => Yii::$app->user->id, ':current_user1' => Yii::$app->user->id]])
->one();

How can I prepare a sql-statement in a sql-statement in ZF2?

I'm new to ZF2 and I've got following problem :
In a db-table I got two id's that refered to another table. And if I
select them, I want to show the names of the players, rather than the
id's saved in the table.
player (id, name)
board (id, playerA, playerB)
playerA and playerB are integers and holding the id of a player, from the players table. I've got along with the skeleton-app, but the only clause I can pass to tableGateway->select() is the where-clause.
Does anyone have an idea? how can I prepare a statement like this in ZF2?
SELECT id, (SELECT name FROM player WHERE id = playerA) AS playerA, (SELECT name FROM player WHERE id = playerB) AS playerB FROM board
The tutorials and references I've found all ends up with a JOIN. But that do not fit here, right?
EDIT:
The following is it, what works fine with the skeleton app
protected $select;
public function fetchAll() {
$this->select = new Select();
$this->select->from('board')
->columns(array('id', 'kindOf', ...))
->join(['pA' => 'player'], 'pA.id = board.playerA', ['playerA' => 'name'])
->join(['pB' => 'player'], 'pB.id = board.playerB', ['playerB' => 'name']);
$resultSet = $this->tableGateway->selectWith($this->select);
return $resultSet;
}
Your problem is'nt a ZF2 problem but a SQL problem. You can write this for example :
SELECT id, pA.name AS playerA, pB.name AS playerB
FROM board
INNER JOIN player AS pA ON pA.id=board.playerA
INNER JOIN player AS pB ON pB.id=board.playerB
In ZF2 :
$select = new Select();
$select->from('board')
->columns('id')
->join(['pA' => 'player', 'pA.id = board.playerA', ['playerA' => 'name'])
->join(['pB' => 'player', 'pB.id = board.playerB', ['playerB' => 'name'])

Yii add one more select to CDbCriteria

I'm relatively new to Yii.
I fell confident with raw SQL but still get a bit lost when it comes to
ORM. So this may be a dummy question.
I've retrieved all necessary records building such CDbCriteria:
$criteria = new CDbCriteria(array(
'select' => 'sum(items) as items',
// 'condition' => 't.items > 0 and order.storage = "'Product::STORAGE_LOCAL . '"',
'condition' => 't.items > 0 and order.storage = "' . Product::STORAGE_LOCAL . '"',
'order' => 'sum(items) DESC',
'with' => array(
'product' => array(
'select' => 'code, title, producer, local_rest',
**// 'select' => 'code, title, producer, sum(local_rest) as local_rest',**
'group' => 'product.code',
)
),
'join' => 'inner join `order` `order` on `t`.`order_id` = `order`.`id`',
// 'group' => '`product`.`code`, `product`.`title`',
'group' => '`product`.`code`',
'together' => true
));
I try to get sum of local_rest field doing group by. Unfortunately it does not return what it should be.
This is how I tried to build in it into CDbCriteria:
// 'select' => 'code, title, producer, sum(local_rest) as local_rest',.
- no luck.
I can get the it using separated query as:
$sum_local_rest = Yii::app()->db->createCommand("
SELECT id,code, title, sum(local_rest) as sum_rest FROM product GROUP BY code
ORDER BY `sum_rest` DESC
");
One more caution - there are duplicate records in product table.
I.e. we have the same product more than one time. But if I use GROUP BY it helps to delimiter this shortcoming. This is due to bad DB design and should be fixed in the future.
The problem is that I need somehow to bind it with CDbCriteria, because it's used by CDataProvider and CDataProvider is used by GridView.
Any tips how to connect these two question in one CDbCriteria?
Thanks in advance
EDIT
Looking at the current answers I feel I need summarize. The main problem is that I need to tell CDbCriteria to retrieve records (bound by HAS_Many connections) and to calculate SUM of all these records and to make CDbCriteria to do GROUP BY of these records.
No other way. I can't do it explicitly. Because I pass CDbCriteria to CDataProvider and it should run queries. This is how things work in Yii (as far as I understand).
//You can merge your criteria like here:
$criteria = new CDbCriteria(); //First criteria
$criteria_2 = new CDbCriteria(); //Second criteria
$criteria->mergeWith($criteria_2); //Merge criteria and criteria_2
SomeModel::model()->findAll($criteria); //Find by criteria
I don't see why something like this shouldn't work:
$criteria = new CDbCriteria;
$criteria->select = array(
"SUM(t.items) as items",
"SUM(product.local_rest) as product_local_rest"
);
$criteria->condition = "t.items > 0 and order.storage = "' . Product::STORAGE_LOCAL . '"';
$criteria->join = 'inner join `order` `order` on `t`.`order_id` = `order`.`id`';
$criteria->with = "product";
$criteria->group = "product.code";
$criteria->together = true;
Since you're setting together to true, the columns of your relation should be available to your query, aliased by the relation's name (product). (Note: to access the result of SUM(product.local_rest) on the models returned by CActiveDataProvider, you'll need to set $product_local_rest as a public property on the class of the returned models.)
Alternatively, if you're more comfortable writing raw SQL, you could use CDbCommand to generate an array of results, and then use CArrayDataProvider instead of CActiveDataProvider. http://www.yiiframework.com/doc/api/1.1/CArrayDataProvider
You also don't have to pass all elements to criteria. Try to split criteria into more code like this:
$criteria = new CDbCriteria();
$criteria->select = 'sum(items) as items, ' . Product::STORAGE_LOCAL;
$criteria->condition = 't.items > 0 and order.storage = ' . Product::STORAGE_LOCAL;
//etc.

Zend fetchall cannot return primary ID

I cannot get primary id array, I try to debug it happens when use joinLeft function
Here my script
//setIntegrityCheck to false to allow joins
$roomModel = new self();
$select = $roomModel->select(Zend_Db_Table::SELECT_WITH_FROM_PART)
->setIntegrityCheck(FALSE);
//performs join aliasing table room_type to t
$select->join(array('t' => 'room_types'), 't.room_type_id = rooms.room_type_id AND num_beds> '.$number_beds);
////performs join aliasing table room_status to s
$select->join(array('s' => 'room_statuses'), 's.room_status_id = rooms.room_status_id');
$select->joinLeft(array('chin' => 'checkin'), 'chin.checkin_date > '.$checkin.' AND chin.checkin_date <'.$checkout.'');
$select->joinLeft(array('chout' => 'checkout'), 'chout.checkout_date >'.$checkin.' AND chout.checkout_date <'.$checkout.'');
$result = $roomModel->fetchAll($select);
What causes it to happen?
one of the tables you are joining also may contain a column named like your primary key and if the row does not exist it will override it with null.
you should choose which columns you want from each table:
$select->join('table', 'condition', array('column1', 'column2', 'column3'));
$select->joinLeft('table', 'condition', array('column1', 'column2', 'column3'));

Categories