Yii relation STAT with multiple columns - php

i'm trying to get a STAT relation from a Review table. This is my code
public function relations()
{
return array(
'avarageRating' => array(SELF::STAT, 'Reviews', array('make_code'=>'make_code', 'model_code'=>'model_code', 'year'=>'year'), 'select' => 'AVG(overall_rating)'),
}
the table would look something like this
make_code | model_code | year | overall_rating
01 | 02 | 2015 | 4.2
01 | 03 | 2014 | 4.0
01 | 02 | 2015 | 3.0
i want to get the overall_rating average for all rows that have the same make_code, model_code and year
example, make_code 01, model_code 02 and year 2015. (4.2+3.0 / 2), $model->avarageRating should give me 3.6
Right now, when i call the relation using $model->avarageRating; i get an error
preg_match() expects parameter 2 to be string, array given
any idea what i'm doing wrong?
EDITED:
function getavarageRating() {
$criteria = new CDbCriteria();
$criteria->select='ROUND(AVG(overall_rating), 1) AS avg, COUNT(overall_rating) AS total';
$criteria->addCondition("make_code=:make_code");
$criteria->addCondition("model_code=:model_code");
$criteria->addCondition("year=:year");
$criteria->params = array(':make_code' => $this->make_code, ':model_code' => $this->model_code, ':year' => $this->year);
$query = Reviews::model()->find($criteria);
return $query;
}
i added this function in my model, and this workws. but i there a way to use relations instead?

Seems you get a collection for your result so you should access by index , try accessing the first element as
$model[0]->avarageRating;

Related

Providing the Custom Name to both Key and Value Pairs of an Array

I have a table named questions in the following form:
Table Name: questions
qn_id | question |
---------------------------------------------------------------
19 | What is your rating on your Team Work?
20 | What is your rating on your Skills?
21 | What is your rating on your Personal Quality?
I have another table named rating as shown below:
Table Name: rating
id | employee_id | question_id | self_score | supervisor_score
-----------------------------------------------------------------
1 | 205 | 19 | 4 | 3
2 | 205 | 20 | 5 | 4
3 | 205 | 21 | 4 | 5
Note: There are two people involved in providing the score. One is supervisee and another is supervisor.
The score provided by the supervisee is kept in the column named self_score. In the table, employee_id is the id of the supervisee. Supervisor also gives the rating to the supervisee for the same question as shown aboove in the table.
I have generated the data from the database as an Array which is shown below:
$params = Array
(
[selfscore_19] => 4
[supervisorscore_19] => 3
[selfscore_20] => 5
[supervisorscore_20] => 4
[selfscore_21] => 4
[supervisorscore_21] => 5
)
Note: In the key named [selfscore_19] , selfscore_ is the string and 19 is the question id.
Questions are same for both - 'self' and 'supervisor'.
So I have appended the strings named 'selfscore' and 'supervisorscore' with the question_id.
In the array shown below, key is: [selfscore_19] which has been appended with the question_id i.e 19 and
the value is score provided by 'self' which is 4.
And other data follows similar pattern.
Attempt:
The code below shows the attempt done by me so far:
Note: I have only shown the main part of the method.
foreach($params as $key => $value){
$exp_key = explode('_', $key);
if($exp_key[0]=='selfscore'){
$arr_result[] = $value;
}
}
foreach($params as $key => $value){
$exp_key = explode('_', $key);
if($exp_key[0]=='supervisorscore'){
$arr_result[] = $value;
}
}
if(isset($arr_result)){
echo '<pre>';
print_r($arr_result);
echo '<pre>';
}
This is the output of the above code:
Current Output:
Array
(
[0] => 4
[1] => 5
[2] => 4
[3] => 3
[4] => 4
[5] => 5
)
Now I want to tranform the Current Output in the form of following Output.
Although I have already researched about this case, but I am finding it a bit tricky.
What modification should I do to achieve the required output?
Suggestions are highly appreciated.
Required Output:
$score['self_score']=array(
array('question_id'=>19,'score'=>4)
array('question_id'=>20,'score'=>5)
array('question_id'=>21,'score'=>4)
);
$score['supervisor_score']=array(
array('question_id'=>19,'score'=>3),
array('question_id'=>20,'score'=>4)
array('question_id'=>21,'score'=>5)
);
Do it with a single loop. Use the first part of $exp_key as the key of the resulting array, and the second part as the value of the question_id key of the sub-array.
foreach ($arr_result as $key => $value) {
$exp_key = explode("_", $key);
$score[$exp_key[0]][] = array("question_id" => $exp_key[1], "score" => $value);
}
I think I'll recommend that you use a UNION to join two simple queries so that your initial resultset is very close to what you want (close enough to simply iterate and/or modify it).
SQL: (Demo)
(SELECT 'group' AS 'self_score', question_id, self_score
FROM rating
WHERE employee_id = 205
ORDER BY id)
UNION
(SELECT 'supervisor_score', question_id, supervisor_score
FROM rating
WHERE employee_id = 205
ORDER BY id)
Resultset:
group | question_id | self_score
------------------|---------------|------------
self_score | 19 | 4
self_score | 20 | 4
self_score | 21 | 5
supervisor_score | 19 | 3
supervisor_score | 20 | 4
supervisor_score | 21 | 5
If you are open to a PDO solution, fetchAll(PDO::FETCH_GROUP) will come in pretty handy.

How do I print out a long BIGINT in Yii in PHP?

When I print a BIGINT in Yii, it is rounding to MAX_INT. How do I print longs in Yii?
foreach ($negativeKeywords as $i=>$v) {
echo "$i: Removing $v->id, $v->campaign_id, $v->keyword, $v->google_id\n";
# 11: Removing 103, 2, gamtech, 2147483647
Real values:
=> select * from negative_keyword where id in (103,413);
id | campaign_id | keyword | match_type | status | google_id | bing_id
-----+-------------+------------+------------+--------+-------------+---------
103 | 2 | gamtech | 3 | 0 | 31883722149 |
=> \d negative_keyword;
Column | Type | Modifiers
...
google_id | bigint |
Here is the migration which created the table
$this->createTable('negative_keyword', [
'id' => Schema::TYPE_PK,
'google_id' => Schema::TYPE_BIGINT,
...
PHP 5.6.12 (cli) (built: Aug 11 2015 13:13:58)
Try this : You need to add max value of Bigint.
public function rules(){
return [
[['number_min'],'number','min'=>10],
[['number_max'],'number','max'=>100],
[['number_min_max'],'number','min'=>10,'max'=>100],
];
}
You can convert it to string while retrieving data through Query:
MYSQL
SELECT CONVERT(google_id, CHAR(10))
FROM negative_keyword;
Increase CHAR length accordingly...
For more info check this Reference
PostgreSQL
By Using to_char(), you can convert it into String in PostgreSQL
to_char(int, text)
For more info check this Reference
Sometimes you need to convert the BIGINT to a VARCHR in Postgres.
$accounts = Account::find()->select(['*', 'google_id' => 'cast(google_id as varchar)'])->all();
The 'number' rule by itself doesn't always work (esp. Postgres 9.4).

Walk through a table to grab unique certificate numbers for shares

The table I am working with is named shares. Assuming $share is an instance of the model Share. A share belongs to a company.
| id | company_id | number_of_shares |
| 31 | 1 | 3 |
| 33 | 1 | 9 |
| 34 | 1 | 4 |
I want to call $share->getCertificate() and have it return a certificate number, these should be:
id 31 -> 1
id 33 -> 2
id 34 -> 3
Note: this increments a unique certificate number based on its location in the table.
Then when I call $share->getDistinctive() I wish to have it return the following:
id 31 -> array('start' => 1, 'end' => 3)
id 33 -> array('start' => 4, 'end' => 13)
id 34 -> array('start' => 14, 'end' => 18)
Note: this increments based on the number of shares starting at 1
Assumptions
Table will always be ordered by id
I am using laravel 4.0.
Happy for someone to recommend a better title so that other people can find the the solution to their problem.
Worked it out - not sure why I thought it would've been more complicated.
getCertificateNumber()
public function getCertificateNumber()
{
$x=1;
foreach($this->company->holdings()->get() as $holding)
{
if($holding->id == $this->id)
{
return $x;
}
$x++;
}
}
getDistinctiveNumbers()
public function getDistinctiveNumbers()
{
$shares=0;
foreach($this->company->holdings()->orderBy('id')->get() as $holding)
{
if($holding->id == $this->id)
{
return ['start'=> $shares + 1, 'end' => $shares + $this->number_shares];
}
$shares += $holding->number_shares;
}
}

How to print specific array entry using variable for position e.g. $array[$x]

With help from others on here, I've got a nested loop on the go that pull a list of months from one sql table and then, for each of those months, it goes through an events table and pulls the respective events.
Table structures are along the lines of:
MonthTable
ID | MonthShort | MonthLong
1 | 2012Oct | October 2012
2 | 2012Sep | September 2012
EventTable
ID | MonthID | Event | Guests | Adults | Children
1 | 1 | Wedding | 200 | 150 | 50
2 | 1 | Bar Mitzvah | 100 | 50 | 50
3 | 1 | Funeral | 100 | 50 | 50
4 | 2 | Birthday | 50 | 30 | 20
5 | 2 | Birthday | 300 | 200 | 100
6 | 2 | Wedding | 200 | 180 | 20
My loop works so that it populates menu A with all available months, then populates menu B with all of the events for that month. You can then click on the event and it displays the relevant information - this is where I'm a bit stuck.
The arrays I've got are similar to the following, the guests array is what I'm trying out atm:
$events = array();
$months = array();
$guests = array();
while ($row = mysql_fetch_array($result)) {
$months[$row["MonthID"]] = $row["MonthLong"];
$events[$row["MonthID"]][] = $row["Event"];
$guests[$row["MonthID"]][] = $row["Guests"];
}
I use a foreach to populate menu B with ($events[$x] as $event). The screen for each event will have an entry similar to the following and this is what I'd like to do (obviously I know this won't work bu it should serve for illustrative purposes):
echo ' Number of guests: ' . print_r($guests[$x])
With guests and events both on the same counter I though it would allow me to print the array entry in the relevant position.
So what I'd like it if you click on "October 2012" and then select "Funeral", the screen would say:
Number of guests: 100
There are actually several dozen records per event but no point going into all of them...
Apologies for the rambling and if this makes no sense! I'm new to PHP and am only really stuck on this bit.
SQL query is built on the following:
$sql = "
SELECT
a.id, b.id AS monthId, a.event, b.monthshort, b.monthlong
FROM
events_table_name AS a
INNER JOIN
month_table_name AS b ON b.id = a.monthId
ORDER BY
b.id, a.id ASC
";
You need make use of the index in the foreach statement. I mean
foreach ($events[$x] as $i => $event) {
...
echo ' Number of guests: ' . print_r($guests[$x][$i]);
}
I would go for a different data structure in PHP. How about this? You might have to change your SQL query to get it, but this is the data structure I'd aim for:
$months = array(
'1' => array(
'long' => 'October 2012',
'events' => array(
'1' => array(
'name' => 'Wedding',
'guests' => '200'
),
'2' => array(
'name' => 'Bar Mitzvah',
'guests' => '100'
),
'3' => array(
'name' => 'Funeral',
'guests' => '100'
)
)
),
'2' => array(
// etc.
)
);
This way, you're able to look up a month; for each month, its events; for each event, its attendance and name.

How do I combine two MySQL rows into one and display them in a table using PHP?

I have a table "exercise_results". People put in their results at the beginning and then two months later put in their results to see how much they improved. Their beginning set has the exercise_type_id of "1" and the end set has the exercise_type_id of "2".
I need a way to display this out into a HTML table that looks like this:
a foreach loop, but that's with single rows. I'm having trouble combining two rows into one. I think this may be as simple as some kind of MySQL join? We identify each person by their person_unique_id.
Here are my fields:
id | person_unique_id | person_name | exercise_type_id | mile_running_time | bench_press_weight_lbs | squat_weight_lbs | date_of_exercise_performed
Sample rows:
1 | J123 | John Smith | 1 | 8 | 200 | 300 | 2010-03-20
2 | J123 | John Smith | 2 | 7 | 250 | 400 | 2010-05-20
3 | X584 | Jane Doe | 1 | 10 | 100 | 200 | 2010-03-20
4 | X584 | Jane Doe | 2 | 8 | 150 | 220 | 2010-05-20
I've tried a few solutions but I'm lost. Any help would be great. Thanks!
EDIT:
In response to the comment below, I would hope for some data like:
array 0 =>
array
'Exercise' =>
array
'person_unique_id' => string 'J123'
'person_name' => string 'John Smith'
'begin_mile_running_time' => string '8'
'end_mile_running_time' => string '7'
1 =>
array
'Exercise' =>
array
'person_unique_id' => string 'X584'
'person_name' => string 'Jane Doe'
'begin_mile_running_time' => string '10'
'end_mile_running_time' => string '8'
You can use GROUP_CONCAT() to get a two rows result like this:
SELECT person_unique_id, person_name,
group_concat( mile_running_time ) AS miles,
group_concat( bench_press_weight_lbs ) AS bench,
GROUP_CONCAT( squat_weight_lbs ) AS squat
FROM exercise_result
GROUP BY person_unique_id
Your result will be like:
J123 | John Smith | 8,7 | 200,250 | 300,400
X584 | Jane Doe | 10,8 | 100,150 | 200,220
And then you can use php explode with the result fields to get the results for each type.
Extract the whole table, or whichever rows are interesting to you, sort on person id, compare person id of each row with the next to see if there is a result to print for all columns in your HTML table. If not, jump to the next and leave the fields blank(or some other solution, maybe ignore persons who have not filled in both fields?).
My PHP skills are limited, so no code example.
$query = mysql_query("select ...your data");
while ($row = mysql_fetch_assoc ($query) ) {
if ($row['exercise_type_id']==1)
$exe1[]=$row;
else
$exe2[]=$row;
}
print_r($exe1);
print_r($exe2);
from what I've understood
edit:
try this
$query = mysql_query("select ...your data");
while ($row = mysql_fetch_assoc ($query) ) {
$rows[]=array('Exercise'=>$row);
}
print_r($rows);
If you are ordering on person_unique_id then exercise_type_id, you can do this. If you have two rows for everyone, you can leave out the if (only use the else):
for( $i = 0; $i < count($exercise_results); $i++ )
{
$first = $exercise_results[$i];
if( !isset($exercise_results[$i+1])
|| $first['person_unique_id'] != $exercise_results[$i+1]['person_unique_id' ) {
$second = array(
'person_name'=>$other['person_name'],
'mile_running_time' => null // fill in the rest with defaults (like null)
);
} else {
$second = $exercise_results[$i+1];
$i++; // skip ahead one, since you've already used the second result.
}
// perform your normal printing, but use $beginning and $end to get the respective results
}

Categories