Basically I have a legacy query in mysql that I will be implement into ActiveRecord,
Legacy Way, as expected
SELECT
a.container_seal,
a.size ,
count(a.size) as bundles,
sum(a.piece) as pieces
FROM pipe a
WHERE a.outgoing_pipe_id IS NULL
GROUP by a.container_seal, a.size
ORDER by a.container DESC
AR Way
$modelPipe = Pipe::find()
->select([
"container_seal",
"size",
"count(size) as bundles",
"sum(piece) as pieces"
])
->where(['outgoing_pipe_id' => NULL])
->groupBy(['container_seal', 'size'])
->orderBy(['container' => SORT_DESC])
->all();
But why, when I debug it,
<pre>
<?php
print_r($modelPipe);
?>
</pre>
The count and sum is not into.
Array
(
[0] => app\models\hanwa\Pipe Object
(
[_attributes:yii\db\BaseActiveRecord:private] => Array
(
[container_seal] => TEMU6099067/ EMCCSQ6566
[size] => 15 x 35 x 0.85 x 6000
)
[_oldAttributes:yii\db\BaseActiveRecord:private] => Array
(
[container_seal] => TEMU6099067/ EMCCSQ6566
[size] => 15 x 35 x 0.85 x 6000
)
[_related:yii\db\BaseActiveRecord:private] => Array
(
)
[_errors:yii\base\Model:private] =>
[_validators:yii\base\Model:private] =>
[_scenario:yii\base\Model:private] => default
[_events:yii\base\Component:private] => Array
(
)
[_behaviors:yii\base\Component:private] => Array
(
)
)
[1] => app\models\hanwa\Pipe Object
(
[_attributes:yii\db\BaseActiveRecord:private] => Array
(
[container_seal] => TEMU6099067/ EMCCSQ6566
[size] => 35 x 35 x 0.75 x 6000
)
Is it Yii2 have another way to use sum and count in case 'select' ?
You shoudl add the pubblic var for bundles and pieces in your pipe model
(for recive the result of query )
class Pipe extends \yii\db\ActiveRecord
{
public $bundles;
public $pieces;
......
Related
I'm having problems when using find to sum the field num_days from table events.
$events = TableRegistry::get('Events');
$query = $events->find('all')
->select(['used' => 'sum(num_days)'])
->first();
Why $query->used is always 0?
print_r($events->find('all')->select(['used' => 'sum(num_days)'])->toArray()) gives,
Array ( [0] => App\Model\Entity\Event Object ( [used] => 6 [[new]] => [[accessible]] => Array ( [*] => 1 ) [[dirty]] => Array ( ) [[original]] => Array ( ) [[virtual]] => Array ( ) [[errors]] => Array ( ) [[invalid]] => Array ( ) [[repository]] => Events ) )
6 is exactly the correct answer for the query and print_r shows it but $query->used is returning always 0.
try $query->order(['used' => 'DESC']); before $query->used
Also, we can add used as protected $_virtual = ['used']; inside Event.php Entity File
I'm trying to get the total budgets of the last x days. I tried the following but the days without budgets are not being returned.
<?php
class Budget extends \Eloquent {
public static function getTotalBudgetsByDay($days = 31)
{
$budgetByDays = self::where('created_at', '>=', \Carbon\Carbon::now()->subDays($days))
->groupBy('date')
->orderBy('date', 'ASC')
->get([
\DB::raw('Date(created_at) as date'),
\DB::raw('COUNT(*) as total')
]);
return array_map(function ($row) {
return $row->getAttributes();
}, $budgetByDays->all());
}
}
$budgetsByDays = \Budget::getTotalBudgetsByDay();
Result:
Array (
[0] => Array
(
[date] => 2015-01-08
[total] => 2
)
[1] => Array
(
[date] => 2015-01-09
[total] => 1
)
[2] => Array
(
[date] => 2015-01-11
[total] => 7
)
)
in this case on 10 not appear in the array
I'm using CakePHP 2.5.2 and having a bit of trouble searching for data efficiently.
In my application I've 3 tables, teams, players, skills... In teams there are 80 records, players 2400 records, skills 2400 records... I want to calculate the average skill of a team...
//Team model
public $actsAs = array('Containable');
public $hasMany = array('Player');
//Player model
public $actsAs = array('Containable');
public $hasOne = array('Skill');
public $belongsTo = array('Team');
//Skill model
public $actsAs = array('Containable');
public $belongsTo = array('Player');
My research is:
$team = $this->Team->find('all', array(
'contain' => array(
'Player' => array(
'Skill'
)
),
));
$this->set('team', $team);
that gives the expected result:
Array
(
[0] => Array
(
[Team] => Array
(
[id] => 1
[name] => my_team_name
)
[Player] => Array
(
[0] => Array
(
[id] => 000000419
[name] => Name
[surname] => Surname
[age] => 21
[team_id] => 1
[Team_id] => 1
[Skill] => Array
(
[id] => 20
[player_id] => 000000419
[skill] => 599
)
), ecc.....
This structure use at least 1680 queries... that are too much for me...
I've tried an other way, that involve just one query, returns a bad data structure but all the information that i need (also redundant). unfortunately follow this way i can not iterate in View to display what i need.
$player = $this->Team->Player->find('all', array(
'contains' => array(
'Skill',
),
that returns
Array
(
[0] => Array
(
[Player] => Array
(
[id] => 000000400
[nome] => my_player_name
[cognome] => my_player_surname
[nation_id] => 380
[age] => 29
[team_id] => 2
)
[Team] => Array
(
[id] => 2
[nome] => my_team_name
)
[Skill] => Array
(
[id] => 1
[player_id] => 000000400
[average] => 632
)
)
ecc.
Is there a way to iterate in VIEV to get the average skill of every team? Any other solutions?
Thanks!
You can use my plugin to solve this issue if you can upgrade CakePHP to 2.6 or later. The plugin has a high compatibility with ContainableBehavior, but generates better queries.
I think that the find operation will execute only 2 queries then.
I would be happy if you try it.
https://github.com/chinpei215/cakephp-eager-loader
Usage
1. Enable EagerLoader plugin
// In your model
$actsAs = ['EagerLoader.EagerLoader'];
If you are afraid that loading my plugin breaks something somewhere, you can also enable it on the fly.
// On the fly
$this->Team->Behaviors->load('EagerLoader.EagerLoader');
2. Execute the same find operation
$this->Team->find('all', ['contain' => ['Player' => ['Skill']]]);
3. See the query log
You will see the query log such as the following:
SELECT ... FROM teams AS Team WHERE 1 = 1;
SELECT ... FROM players AS Player LEFT JOIN skills AS Skill ON Player.id = Skill.player_id WHERE Player.id IN ( ... );
if you feeling that query searching so many tables (ie, models) then
you can unbind those model, before performing search with find()
if you want to fetch some particular column of a table, then remove
others column by selecting "fields" in find().
At the moment "matrix_mct_versions" is a table with 73 entries. When I run this query the "version_count" always returns 73, ie the full number of rows. When I run the sub select query on its own i get the real count as per the com_ID param sent. I cannot see what I am doing wrong with this.. can anyone help?
SELECT
a_ID as com_ID,
option_number,
comment,
word_count,
gender,
sample,
(
SELECT
count(a_ID)
FROM
matrix_mct_versions
WHERE
com_ID = com_ID
) as version_count
FROM
matrix_mct
WHERE
attribute_number = :attribute_number AND
grade_number = :grade_number AND
attribute_type = :attribute_type
ORDER BY
option_number
Returns results like this:
[0] => Array
(
[com_ID] => 678
[option_number] => 1
[comment] => TODO primary function missing for controller y
[word_count] => 7
[gender] => 2
[sample] => 0
[version_count] => 73
)
[1] => Array
(
[com_ID] => 679
[option_number] => 2
[comment] => TODO make this green
[word_count] => 4
[gender] => 2
[sample] => 0
[version_count] => 73
)
[2] => Array
(
[com_ID] => 680
[option_number] => 3
[comment] => TODO make this better
[word_count] => 4
[gender] => 2
[sample] => 0
[version_count] => 73
)
At least one problem is your subquery. It is not correlated. I think you mean:
(SELECT count(a_ID)
FROM matrix_mct_versions
WHERE matrix_mct_versions.com_ID = matrix_mct.com_ID
) as version_count
I am trying to run a db query in drupal where, the content type has a node association field, and I am trying to get all notes of that type, where the NID of the current node matches any of the nodes specified in said note association field.
a visual example
Nodetype1
-- Node Association Field
NodeType2
I would like to get all Nodetype1's where Node Association Field matches the NID of Nodetype2 that is currently loaded.
My current db query is like so:
db_query("SELECT * FROM field_data_field_promo_profile WHERE field_promo_profile_nid=".$N->nid);
and this returns nothing, when i know for a fact that such a node exists, I also tried dropping the WHERE statement and it returns an array like this:
DatabaseStatementBase Object ( [dbh] => DatabaseConnection_mysql Object ( [shutdownRegistered:protected] => [target:protected] => default [key:protected] => default [logger:protected] => [transactionLayers:protected] => Array ( ) [driverClasses:protected] => Array ( [SelectQuery] => SelectQuery [DatabaseSchema] => DatabaseSchema_mysql [MergeQuery] => MergeQuery [DatabaseTransaction] => DatabaseTransaction [UpdateQuery] => UpdateQuery [InsertQuery] => InsertQuery_mysql ) [statementClass:protected] => DatabaseStatementBase [transactionSupport:protected] => 1 [transactionalDDLSupport:protected] => [temporaryNameIndex:protected] => 0 [connectionOptions:protected] => Array ( [database] => cityhound_dev [username] => blahblah [password] => blahblah [host] => localhost [port] => [driver] => mysql [prefix] => Array ( [default] => ) ) [schema:protected] => DatabaseSchema_mysql Object ( [connection:protected] => DatabaseConnection_mysql Object *RECURSION* [placeholder:protected] => 0 [defaultSchema:protected] => public [uniqueIdentifier:protected] => 4fd7fba9e563e2.50177866 ) [prefixes:protected] => Array ( [default] => ) [prefixSearch:protected] => Array ( [0] => { [1] => } ) [prefixReplace:protected] => Array ( [0] => [1] => ) ) [queryString] => SELECT * FROM field_data_field_promo_profile )
Any one have some ideas ?
db_query() returns an iterable object, so you just need to iterate over it:
$result = db_query("SELECT * FROM field_data_field_promo_profile WHERE field_promo_profile_nid=".$N->nid);
foreach ($result as $row) {
$entity_id = $row->entity_id;
// etc...
}
You should use parameters in your queries to prevent SQL injections.
For instance the query above should look like this:
$result = db_query("SELECT * FROM {field_data_field_promo_profile} p
WHERE p.field_promo_profile_nid = :nid ", array(':nid' => $N->nid);
foreach ( $result as $row ) {
$entity_id = $row->entity_id;
// etc...
}