0

I have a table with 1000 records and a corresponding data history of 5 years, including events. The table structure looks like this at the moment:

id|date|reference_id|account_id|dataSet|price|title|type|description

1|2006-01-03|ID00001|1|dataSet01|44.23|Analyst opinion change|A|Upgrade by Bank from Sell to Hold
2|2006-01-03|ID00002|1|dataSet02|62.75|||
3|2006-01-03|ID00003|1|dataSet03|25.95|Dividend|D|Amount: 0.22
4|2006-01-03|ID00004|2|dataSet04|31.81|||
5|2006-01-03|ID00005|3|dataSet05|78.20|||
6|2006-02-01|ID00001|1|dataSet01|45.85|Dividend|D|Amount: 0.30
7|2006-02-01|ID00002|1|dataSet02|59.37||
8|2006-02-01|ID00003|1|dataSet03|27.59|Dividend|D|Amount: 0.26
9|2006-02-01|ID00004|2|dataSet04|34.24|||
10|2006-02-01|ID00005|3|dataSet05|83.42|||
11|2006-03-01|ID00001|1|dataSet01|45.54|Analyst opinion change|A|Upgrade by Bank from Sell to Hold
12|2006-03-01|ID00002|1|dataSet02|60.86|||
13|2006-03-01|ID00003|1|dataSet03|27.04|Downgrade by Bank from Buy to Hold
14|2006-03-01|ID00004|2|dataSet04|36.04|||
15|2006-03-01|ID00005|3|dataSet05|84.32|||

I want to render the data depending on account_id (in this case account_id = 1) to get the following JSON:

{
"data": [{
    "date": "2006-01-03",
    "dataSet01": "44.23",
    "dataSet02": "62.75",
    "dataSet03": "25.95"
}, {
    "date": "2006-02-01",
    "dataSet01": "45.85",
    "dataSet02": "59.37",
    "dataSet03": "27.59"
}, {
    "date": "2006-03-01",
    "dataSet01": "45.54",
    "dataSet02": "60.86",
    "dataSet03": "27.04"
}],
"events": [{
    "dataSet01": [{
        "date": "2006-01-03",
        "title": "Analyst opinion change",
        "text": "A",
        "description": "Upgrade by Bank from Sell to Hold"
    }, {
        "date": "2006-02-01",
        "title": "Dividend",
        "text": "D",
        "description": "Amount: 0.30"
    }, {
        "date": "2006-03-01",
        "title": "Analyst opinion change",
        "text": "A",
        "description": "Upgrade by Bank from Sell to Hold"
    }]
},{
    "dataSet03": [{
        "date": "2006-01-03",
        "title": "Analyst opinion change",
        "text": "A",
        "description": "Upgrade by Bank from Sell to Hold"
    }, {
        "date": "2006-02-01",
        "title": "Dividend",
        "text": "D",
        "description": "Amount: 0.30"
    }, {
        "date": "2006-03-01",
        "title": "Analyst opinion change",
        "text": "A",
        "description": "Downgrade by Bank from Buy to Hold"
    }]
}]
}

I'm struggling to build the json though. As of right now I'm rendering the data like this:

$query = "SELECT date, price 
FROM datatable
WHERE account_id = 1
ORDER BY date ASC";
$result = mysql_query( $query );

$data = array();
while ( $row = mysql_fetch_assoc( $result ) ) {
$data[] = $row;
}

return json_encode( $data );

Obviously this returns the json with price as label for each record value (price). How should the query look like instead to render the above json example?

Matt S
  • 14,976
  • 6
  • 57
  • 76
Philipp M
  • 3,306
  • 5
  • 36
  • 90
  • You should avoid learning or writing new code using PHP's `mysql_*` functions. They have been removed in the latest version and your code won't work in the future. Please read [Why shouldn't I use mysql_* functions in PHP?](http://stackoverflow.com/questions/12859942/why-shouldnt-i-use-mysql-functions-in-php) for information on why and what to replace them with. – Matt Raines May 30 '16 at 19:39
  • I will :-) Thanks Matt. – Philipp M May 30 '16 at 19:42

1 Answers1

1
$query = "SELECT * 
          FROM datatable
          WHERE account_id = 1
          ORDER BY date ASC";

$result = mysql_query( $query );

// Define temporary arrays
$data = array();
$events = array();

while ( $row = mysql_fetch_assoc( $result ) ) {

   // Assemble the data grouped by date and dataset
   if ( !isset($data[$row['date']]) )
   {
      $data[$row['date']] = array(
          'date' => $row['date'],
      );
   }

   // Inject dataSet in $data grouped by date
   if ( !isset($data[$row['date']][$row['dataSet']]) )
   {
      $data[$row['date']][$row['dataSet']] = $row['price'];
   }

   // Assemble events grouped by dataSet
   if ( !isset($events[$row['dataSet']]) )
   {
      $events[$row['dataSet']] = array();
   }

   $events[$row['dataSet']][] = array(
      'date' => $row['date'],
      'title' => $row['title'],
      'text' => $row['type'],
      'description' => $row['description']
   );
}

// Remove date keys
$data = array_values($data);

return json_encode(array(
    'data' => $data,
    'events' => $events
));
James A
  • 775
  • 5
  • 11
  • Syntax ] was missing after // Assemble the data grouped by date and dataset ... if ( !isset($data[$result['date']]) ) ... Now it returns the following json: {"data":[{"date":null,"":null}],"events":{"dataSet01":[{"date":null,"title":null,"text":null,"description":null}]}} The actual table only consist of the records dataSet01. Might this be the case why null? I'll try to add more data ... and test again .. – Philipp M May 31 '16 at 09:07
  • Sorry, I made a huge typo. I edited the answer to reflect the correct syntax - I extensively used `$result` variable to get the values from the row, but it must be `$row` in the first place. Please test. – James A May 31 '16 at 09:18
  • On my local machine I 'echo' json_encode(); and there the "data": json is rendering. Too long to post though. Yet the "events" part is empty and looks like this: "events":{"dataSet01":[{"date":"2000-01-03","title":"","text":"","description":""}]}} Live I 'return' json_encode(); and here it's empty: {"data":[],"events":[]} In another instance I had to include 'true' to the json_encode( $data, true ); when using return. How does it look like when adding 'true'? – Philipp M May 31 '16 at 09:41
  • Ok ... with return json_encode( array( 'data' => $data, 'events' => $events ), true ); ... the "data" part is rendering live as well ... but not the "events" part. Same issue as local. – Philipp M May 31 '16 at 09:47
  • Might the 'events' issue be because of the empty values that exist in some rows? "events":{"dataSet01":[{"date":"2000-01-03","title":"","text":"","description":"‌​"}]}} – Philipp M May 31 '16 at 12:06
  • For the `$events`, please check the field names of your database and make sure it matches `$row['title']`, `$row['type']`, and `$row['description']`. If the data in the database are empty, you will be getting an empty results too. So to test it, just temporarily use this in your query: `WHERE account_id = 1 AND title != '' AND type != '' AND description != ''` – James A May 31 '16 at 12:31
  • As for how json_encode behaves, please refer to the manual from php.net: http://php.net/manual/en/function.json-encode.php. – James A May 31 '16 at 12:32
  • With using WHERE account_id = 1 AND title != '' AND type != '' AND description != '' I do now get one set of events for each record (now I uploaded 2 record types with same history but different values). So it looks like: "events":{"dataSet01":[{"date":"2009-01-23","title":"Analyst opinion change","text":"A","description":"Downgrade from Davenport from Buy to Neutral"}],"dataSet03":[{"date":"2009-01-23","title":"Analyst opinion change","text":"A","description":"Downgrade from Davenport from Buy to Neutral"}]}}. Yet, the amount of "data" records shrinked by about 1/100. – Philipp M May 31 '16 at 12:59
  • With using OR ... WHERE account_id = 1 OR title != '' OR type != '' OR description != '' I get the full set of "data" records but only one set of each "events" record. So just like the one before. But there should be around 50 events for each. – Philipp M May 31 '16 at 13:12
  • Glad the JSON data appears already. With the shrinking of the records, it's a separate issue. It really depends to you if you're going to exclude records with empty fields, but it's recommended to exclude it in your report if records with empty fields doesn't make any sense. How you exclude them, it fully depends to you - you can use `WHERE account_id = 1 AND (title != '' OR type != '' OR description != '')` too. Don't use `WHERE account_id = 1 OR` because the results will include records with other account_id. – James A May 31 '16 at 13:14
  • I want to have all the records both for "data" and "events". With WHERE account_id = 1 AND (title != '' OR type != '' OR description != '') ... the result for "data" is reduced to 1/100 and again only one record for "events". It looks like "events" is not making the loop ... since there should be about 100 events – Philipp M May 31 '16 at 13:28
  • Now all of "data" and "events" gets rendered :-) ... but the load is so high ... my browser freezes. Is it possible to exclude dates in "events" where there is no record for this particular date? Since I have a daily history of "data" ... but only a monthly history of "events" ... So there is always "data" for a specific event, but there could be no "event" on the same date where there is a specific "data" record available ... – Philipp M May 31 '16 at 14:05
  • Split the assignment of `$data` and `$events` in two separate query. For the `$data` query, query for everything: `WHERE account_id = 1`. For the `$events` query, filter all non-essential rows: `WHERE account_id = 1 AND (title != '' OR type != '' OR description != '')` – James A May 31 '16 at 14:22