I am having a bit of trouble getting the proper format of json string.
I have a database table that looks something like this:
Table Columns: emp month sales
Table rows: Bob 1 100
Bob 2 150
Jane 1 125
Jane 2 130
Mary 1 110
Mary 2 130
Within drawChart(), I can create something like this statically:
var data = google.visualization.arrayToDataTable([
['Month', 'Bob', 'Jane', 'Mary],
['Jan', 100, 125, 110],
['Feb', 150, 130, 130]
]);
In the end, the json string needs to look like this:
{"cols":[{"label":"Month","type":"string"},
{"label":"Bob","type":"number"},
{"label":"Jane","type":"number"},
{"label":"Mary","type":"number"}],
"rows":[{"c":[{"v":100},{"v":125},{"v":110}]},
{"c":[{"v":150},{"v":130},{"v":130}]}]}
But I am having trouble pulling from the table to come up with proper json formatting that is equivalent to the above. I am following the steps from here... PHP MySQL Google Chart JSON - Complete Example
But that example is only for a single data set. if you were to add multiple weeks instead of having just one data set, how do run the query?
To get your data in the format you want, you have to pivot your data. Some databases support pivotting, but others like MySQL don't. If you are stuck without pivot support, then you have to resort to trickery to make it happen. Here's one way you could do it:
SELECT
month,
SUM(if(employee = "Bob", sales, 0)) AS Bob,
SUM(if(employee = "Jane", sales, 0)) AS Jane,
SUM(if(employee = "Mary", sales, 0)) AS Mary
FROM myTable
GROUP BY month
This requires that you know ahead of time what the employee names are so that you can write the SQL statement (either when you write the code, or you could pull them from another SQL query and write a dynamic SQL query).
Asgallent, thank you. Your response gave me the direction I needed. I was able to do it all dynamically via SQL. I made two queries: 1 to the "saleperson" table to get the names, and then another to pivot the data as you suggested. For anyone else that might find this helpful, here is the code I have.
The queries (Note: I am using codeigniter):
$sp_qry = $this->db->query('select * from salespeople');
$qryString="";
foreach ($sp_qry->result_array() as $row)
{
$qryString.= ",SUM( IF( `salespeople_id` =" . $row['salespeople_id'] . ", `num_sold` , 0 ) ) AS " . $row['name'];
}
$qry= "SELECT `month` " . $qryString . " FROM `product_sales`
GROUP BY `month`";
$query = $this->db->query($qry);
return $query->result_array();
and in my viewing page
$rows = array();
$table = array();
$cols = array();
$cols[] = array('label' => 'Month', 'type' => 'string');
foreach ($salespeople as $sp)
{
$cols[] = array('label' => $sp['name'], 'type' => 'number');
}
$table['cols'] = $cols;
foreach ($sales as $chart_item)
{
$tmp=array();
$tmp[] = array('v' => (string) $chart_item['month']);
foreach ($salespeople as $sp)
{
$name=$sp['name'];
$tmp[] = array('v' => (int) $chart_item[$name]);
}
$rows[] = array('c' => $tmp);
}
$table['rows'] = $rows;
$jsonTable = json_encode($table);
Related
I have this little query that produces the percentage of responses correctly.
$pdo->query("SELECT avg(pineapple = 'yes')*100 FROM responses");
But what I need to do, is get columns question1,2,3,4 columns together where they are arrayed as columnname => percentage for my graph.
Since I'm not getting two fields in the SELECT, I am unclear how to move forward to set up array like I have before:
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
$jsnarray = array();
$json = json_encode($results);
foreach($results as $k => $v){
$jsnarray[] = array('question' => $results[$k]['COLUMN???'], 'value' => $results[$k]['question1']);
};
Update:
To clarify desired output: an array like:
[column1name] => column yes response %
[column2name] => column2 yes response %
so it would theoretically be:
[pineapple] => 55%
[cheesecurds] => 80%
Which allows the bar graph to be labeled pineapple with the value of 55% and so on.
You should normalize your database design. With your current design, you have to list each column separately. What happens if you need to add a new ingredient?
You could modify your existing SQL to calculate an average of each column like so:
SELECT
avg(pineapple = 'yes')*100 AS pineapple,
avg(mushroom = 'yes')*100 AS mushroom,
avg(anchovy = 'yes')*100 AS anchovy,
avg(cheesecurd = 'yes')*100 AS cheesecurd
FROM responses
Then in PHP, you can just access it as you normally would with any other column.
$averages = $stmt->fetch(PDO::FETCH_ASSOC);
echo "Anchovies: ".$averages['anchovy'];
For a non normalized database like one using imports from google forms:
$stmt = $pdo->query("SELECT 100*avg(pineapple = 'yes') AS Pineapple, 100*avg(pepperoni = 'yes') AS Pepperoni, 100*avg(mushrooms = 'yes') AS Mushrooms, 100*avg(anchovies = 'yes') AS Anchovies FROM responses");
$averages = $stmt->fetch(PDO::FETCH_ASSOC);
$jsonEncodedData=json_encode($averages);
header( 'Content-type: application/json' );
echo $jsonEncodedData;
I did 100*avg for percentage.
Again, don't use this if you can help it.
I am trying to print my data and encode it into JSON. I'm extracting the data from my MySQL database for a quiz. The data that I am trying to extract 1 question, 1 category and 4 options to make a set of quiz. I think I nearly got it how to make it work but I failed to find out how. This was the result check in this link.
Paste the JSON to this link so that you can easily format it. From that JSON data, I want to output like this for each question:
"What is the approximate number of islands that comprise the Philippines?",
"Philippine Geography",
[
{
"quiz_choice_id":"5",
"choice":"7000",
"is_correct_choice":"1"
},
{
"quiz_choice_id":"6",
"choice":"6000",
"is_correct_choice":"0"
},
{
"quiz_choice_id":"7",
"choice":"8000",
"is_correct_choice":"0"
},
{
"quiz_choice_id":"8",
"choice":"9000",
"is_correct_choice":"0"
}
],
This is my code for that:
<?php
/**
* Created by PhpStorm.
* User: Muhammad
* Date: 19/04/2016
* Time: 00:46
*/
require_once('Database_Connect.php');
$questions_query = "SELECT question, quiz_choice_id, choice ,is_correct_choice, category FROM category_question cq, question q, question_choices qc WHERE q.quiz_question_id = qc.quiz_question_id AND q.cat_ques_id = cq.cat_ques_id LIMIT 10";
$questions_query_result = mysqli_query($con, $questions_query) or die("error loading questions");
$questions_results = array();
encode_result($questions_query_result);
function encode_result($result)
{
//$response = array();
$questions = array();
//$choices = array();
while ($r = mysqli_fetch_array($result)) {
//$response[] = $r;
//$questions = array('question' => $r[0]);
$questions[] = $r['question'];
$questions[] = $r[4];
$choices[] = array('quiz_choice_id' => $r[1], 'choice' => $r[2], 'is_correct_choice' => $r[3]);
$questions[] = $choices;
//array_push($questions, $questions['question']);
//array_push($questions_results, $questions);
}
echo json_encode(array('questions'=>$questions));
}
mysqli_close($con);
The design of the database is this:
I can't find a way to make it work because from the database quiz_choice_id,choice, is_correct_choice are in a different table but I combined all into one table as you can see in my SQL statement $questions_query. Please let me know how can I fix this. Thanks in advance.
Do you want the json to look like this?
[ {
"question" : "What is the approximate number of islands that comprise the Philippines?",
"category" : "Philippine Geography",
"choices" : [
{
"quiz_choice_id":"5",
"choice":"7000",
"is_correct_choice":"1"
},
{
"quiz_choice_id":"6",
"choice":"6000",
"is_correct_choice":"0"
},
{
"quiz_choice_id":"7",
"choice":"8000",
"is_correct_choice":"0"
},
{
"quiz_choice_id":"8",
"choice":"9000",
"is_correct_choice":"0"
}
]
},{
..... // next question
}]
You'll have to do something like this, but I have no idea what the results of the query is.
$questions = array();
while ($r = mysqli_fetch_array($result)) {
$key = $r['quiz_question_id']; // you need a key here that is unique to the question, so i think this will do looking at the schema you posted, this will group them in that segment of the array.
if( !isset( $questions[$key] ) ){
//if we never had this question, create the top level in the results
$questions[$key] = array(
'question' => $r['question'],
'category' => $r['category'],
'choices' => array()
);
}
//add in the choices for this question
//on the next iteration, the key is the same so we only do this part
//and append that rows choices to the previous data using $key to match the question
$questions[$key]['choices'][] = array('quiz_choice_id' => $r['quiz_choice_id'], 'choice' => $r['choice'], 'is_correct_choice' => $r['is_correct_choice']);
}
Make sure to add quiz_question_id to your query if this is the questions id, unique identifier. Essentially this will group them together, as this will be the same for each row with that question's choices.
I added string keys to the output, I wouldn't mix using string keys and numbered index. I hope I mapped them out right.
Also I haven't tested this at all, so sorry if there are any syntax errors.
I am having a bit of trouble with this for loop here and hope to get some help !
So I will recreate a simplified version of the loop here:
foreach($quote as $key => $item) {
if(isset($item['dbid'])){
$q_sql = new mysql_builder2('quote',3);
} else {
$q_sql = new mysql_builder2('quote',2);
}
$q_sql->addArgument('name', $name);
$q_sql->addArgument('curr', $curr);
foreach($term[$key] as $data) {
if(isset($data['term_id']) {
$t_sql = new mysql_builder2('details',3);
} else {
$t_sql = new mysql_builder2('details',2);
}
$t_sql->addArgument('date', $date);
$t_sql->addArgument('term', $termnum);
mysqli_query($dbc, $t_sql->build());
}
mysqli_query($dbc, $q_sql->build());
}
Okay, so I think I got it all right here.
EDIT: Before the loops I have the following :
$quote = $_POST['quotes'];
$term = $_POST['terms'];
Inside the HTML the name of these elements is structured like so:
quotes[1][name]
quotes[1][curr]
terms[1][1][date]
terms[1][1][termnum]
and then if there's a second:
quotes[2][name]
quotes[2][curr]
terms[2][1][date]
terms[2][1][termnum]
terms[2][2][date]
terms[2][2][termnum]
etc..
Explaination:
First, mysqli_builder2 is a premade function that creates SQL queries.. When the value is 3, it sets UPDATE, when it's 2 it does INSERT
Now, what will happen is a user will fill out a form and the data will go into two tables, Quote and Details. For each single entry into Quote, there can potentially be multiple in Details (note: I've left out a lot of fields in my example code to save space but there are links between the 2 tables).
My problem here is when I run this for a very simple UPDATE, the second foreach loops runs one extra time always, and it is always an INSERT with random values for each field.. I can't seem to figure why this is happening because it works 100% properly for the first foreach loop..
Example array output when submit:
Array
(
[0] => UPDATE quote SET job_id = 2, wo_id = 9952, quote_num = '1a', revenue = '100.00', cost = '100.00', currency = 1, term = 1 WHERE id = 5857;
)
Array
(
[0] => UPDATE details SET user_id = 532, job_id = 2, wo_id = 9952, quote_num = '1a', percent = 10, term = 1, active = 1, status = 0, date_picked = '2015-02-04', date_submitted = now() WHERE id = 588;
[1] => INSERT INTO details(user_id, job_id, wo_id, quote_num, percent, term, active, status, date_picked, date_submitted) VALUES(532, 2, 9952, '1a', 6, 6, 1, 0, '1969-12-31', now());
)
This INSERT should not be there at all (notice the date going in) ..
Anyways, I'm kind of stuck here and any help is appreciated. If you need any other info just ask :)
Thanks !
Are you sure you copy the code as is?
you have got syntax error:
if(isset($data['term_id']) {
should be:
if(isset($data['term_id'])) {
I'm creating an API for my mobile application. I'm developing this with PHP MYSQL and the Slim framework (which is largely irrelevant for this problem).
I'm trying to pull multiple "venues" from my mysql database, and retrieve multiple "venue_images" for each "venue". The database:
venues venue_images
------ ------------
id PK image_venue_id FK (to venues)
venue_name image_path
active
I then need to output the data in this format:
{
"completed_in":0.01068,
"returned":10,
"results":[
{
"venue_id":"1",
"venue_name":"NameHere",
"images": [
{
"image_path":"http://www.pathhere.com"
},
{
"image_path":"http://www.pathhere2.com"
}
]
}
]
}
So basically, the images are iterated multiple times for each venue.
My current code is:
$sql = "
SELECT
venues.id, venues.venue_name, venues.active,
venue_images.image_venue_id, venue_images.image_path
FROM
venues
LEFT JOIN
venue_images ON venue_images.image_venue_id = venues.id
WHERE
venues.active = 1
LIMIT 0, 10
";
$data = ORM::for_table('venues')->raw_query($sql, array())->find_many();
if($data) {
foreach ($data as $post) {
$results[] = array (
'venue_id' => $post->id,
'venue_name' => $post->venue_name,
'images' => $post->image_path
);
}
//Build full json
$time = round((microTimer() - START_TIME), 5);
$result = array(
'completed_in' => $time,
'returned' => count($results),
'results' => $results
);
//Print JSON
echo indent(stripslashes(json_encode($result)));
} else {
echo "Nothing found";
}
My current code works, however it produces this:
{
"completed_in":0.01068,
"returned":10,
"results":[
{
"venue_id":"1",
"venue_name":"The Bunker",
"images":"https://s3.amazonaws.com/barholla/venues/1352383950-qPXNShGR6ikoafj_n.jpg"
},
{
"venue_id":"1",
"venue_name":"The Bunker",
"images":"https://s3.amazonaws.com/barholla/venues/1352384236-RUfkGAWsCfAVdPm_n.jpg"
}
]
}
There's two images for "The Bunker". Instead of storing the images within the venue array, it's creating a duplicate row of "The Bunker", with the second image. Like I said earlier, I need to have multiple images iterating within each venue. Any help would be much appreciated! Thanks!
You want to use GROUP_CONCAT
Something like this (not 100% accurate probably :) )
$sql = "
SELECT
v.id, v.venue_name, v.active,
GROUP_CONCAT(i.image_path) as venue_image_string
FROM
venues v
LEFT JOIN
venue_images i ON i.image_venue_id = v.id
WHERE
v.active = 1
GROUP BY i.image_venue_id
LIMIT 0, 10
";
You may have to fiddle a little but should put you on the right track (note: provides venue_image_string as CSV)
Why can't you use multiple queries instead of..? Its faster and simple..!
$sql = "SELECT venues.id, venues.venue_name, venues.active FROM venues WHERE venues.active = 1 LIMIT 0, 10";
$data = ORM::for_table('venues')->raw_query($sql, array())->find_many();
if($data) {
foreach ($data as $post) {
$results[] = array ();
$sql = "SELECT image_path FROM venue_images WHERE image_venue_id = $post->id";
$images = ORM::for_table('venue_images')->raw_query($sql, array())->find_many();
$results[] = array (
'venue_id' => $post->id,
'venue_name' => $post->venue_name,
'images' => $images);
}
//Build full json
$time = round((microTimer() - START_TIME), 5);
$result = array(
'completed_in' => $time,
'returned' => count($results),
'results' => $results
);
//Print JSON
echo indent(stripslashes(json_encode($result)));
} else {
echo "Nothing found";
}
In my database I have a field called "modules" - info data looks like this: 1, 4, 1, 3
I want to list/output all data via PHP with the numbers 1 - all other numbers have to be ignored.
I want to check the output result via an array NOT via mySQL
Any suggestion how I can do that?
$list_modules = array();
$res_m = $db->Execute("SELECT modules FROM users u WHERE user_id = '".$user->id."'");
while ( $m = $res_m->GetNext() ) {
$list_modules = array($m['modules']);
}
print_r($list_modules); //Output below
Example (Output):
Array
(
[0] => 1, 4, 1, 3
)
You can do that in you MySQL with a WHERE clause. Depending on the column name in the database:
SELECT column_name FROM table WHERE column_name = 1;
Note: In your question it looks like you tried to list a range:
with the numbers 1 - all other numbers have to be ignored.
If you meant to put a range (e.g. 1 - 4) then your WHERE clause would be:
WHERE column_name BETWEEN 1 AND 4
You should test for that in your MySQL query:
SELECT * FROM `TABLE` WHERE `modules` = 1;
Or, alternatively, if that's not possible..
Loop with foreach and test for 1?
$array = array(1,4,1,3);
foreach ($array as $element) {
if ($element == 1) { echo 1; }
}
This should do it... there is really no other way seeing at the col is Varchar, you also need to eliminate strings like 15, 21, etc. so %1% will not work.
SELECT modules FROM users WHERE user_id = ".$user->id." AND modules LIKE % 1,%
Give it a shot and let me know if it works.
You stated in your comment that the modules field contains comma-separated values, is that right? I reckon that the modules field is VARCHAR, CHAR, or any other string. If so, you could use a query like:
SELECT * FROM `tableName` WHERE `modules` LIKE '%1,%';
There may be other solutions, probably more optimal, but this one should perform well, I think.
Meh found the solution I could use.
$list_modules = array();
$query = "SELECT modules FROM users WHERE user_id = ".$user->id."";
$res_m = $db->Execute($query);
while ( $m = $res_m->GetNext() ) {
$list_modules = array('id' => $m['modules']);
}
$modules = explode(",",$list_modules['id']);
foreach ($modules as $key => $value) {
if($value == 1){
// list data
}
}
}