I am pulling data from three MySQL tables to produce a bootstrap dataTable via AJAX and JSON in PHP.
I have multiple organizational units (Unit 1, Unit 2, Unit 3, etc.) I also have multiple program types (Beginning, Intermediate and Advanced). Finally, I want to show two years data (2105 and 2014) for each organizational unit side-by-side.
In other words, the resulting table would be structured like this (with one row of dummy values for the Beginning program type):
Unit 1 Unit 2 Unit 3
2015 2014 2015 2014 2015 - 2014
Beginning 7 9 136 152 0 3
Intermediate
Advanced
The JSON object that will create and fill this dataTable would need to look something like:
[{"program_category":"Beginning","unit_1":{"2015":"7","2014":"9"},
"unit_2":{"2015":"136","2014":"152"},
"unit_3":{"2015":"0","2014":"3"}}]
So far, I've been able to write a SQL query that produces a JSON string that gets me pretty close, but as you can see the, 'program_type' repeats itself for each organizational unit:
Here's the SQL:
select all_programs_test.program_category as program_category, report_db.unit,
sum(case when all_programs_test.year = '2015' then 1 else 0 end) yr_2015,
sum(case when all_programs_test.year = '2014' then 1 else 0 end) yr_2014
from all_programs_test
JOIN report_db on report_db.id = all_programs_test.id
group by all_programs_test.program_category,report_db.unit
Which I then json_encode in PHP:
while($row = mysql_fetch_assoc($query4)) {
$query4_result[] = array (
'program_category' => $row['program_category'],
$row['unit'] => array(
'2015' => $row['yr_2015'],
'2014' => $row['yr_2014']
)
);
which then produces
[{"program_category":"Beginning","unit_1":{"2015":"7","2014":"9"}},
{"program_category":"Beginning","unit_2":{"2015":"136","2014":"152"}},
{"program_category":"Beginning","unit_3":{"2015":"0","2014":"3"}}]
As you can see in the json object snippet above, 'Beginning' is repeated for each organizational unit. Any ideas on how to get to this instead:
[{"program_category":"Beginning","unit_1":{"2015":"7","2014":"9"},
"unit_2":{"2015":"136","2014":"152"},
"unit_3":{"2015":"0","2014":"3"}}]
Thanks!
Try this:
$category_aux = '';
$record_aux = array();
while($row = mysql_fetch_assoc($query4)) {
if ($category_aux !== $row['program_category']){
$category_aux = $row['program_category'];
if ( ! empty($record_aux)) {
$query4_result[] = $record_aux;
}
$record_aux = array();
$record_aux['program_category'] = $category_aux;
}
$record_aux[$row['unit']] = array(
'2015' => $row['yr_2015'],
'2014' => $row['yr_2014']
);
}
// For the last one.
$query4_result[] = $record_aux;
I have built an static version of your code to try to reproduce your issue however it worked with no issues.
I think the problem may have something to do with your grouping in the query. Can you maybe show us the result of the query?
Related
I'll note that this is a very special case, hence the question to begin with. Under normal circumstances, such a function would be simple:
I have an array named $post_id, which contains 5 values
(Each numerical)
In order to print each value in the array, I use the following loop:
.
for ($i = 0; $i < $num; $i++)
{
echo $post_id[$i] . ' ';
}
...Which prints the following: 49, 48, 47, 46, 43
3. In my database, I have a table that looks like this:
post_categories
_____________________
post_id | category
__________|__________
43 | puppies
43 | trucks
46 | sports
46 | rio
46 | dolphins
49 | fifa
4. So, using the data in the array $post_id, I'd like to loop a database query to retrieve each value in the category column from the post_categories table, and place them into uniquely named arrays based on the "post id", so that something like...
echo $post_id_49[0] . ' ', $post_id_46[1];
...Would print "fifa rio", assuming you use the above table.
An example of such a query:
//Note - This is "false" markup, you'll find out why below
for ($i = 0; $i < $num; $i++)
{
$query = "SELECT category FROM post_categories WHERE post_id = $post_id[$i]";
fakeMarkup_executeQuery($query);
}
Why is this a "special" case? For the same reason the above query is "false".
To elaborate, I'm working inside of a software package that doesn't allow for "normal" queries so to say, it uses it's own query markup so that the same code can work with multiple database types, leaving it up to the user to specify their database type which leaves the program to interpret the query according to the type of database. It does, however, allow the query to be stored in the same "form" that all queries are, like "$result = *query here*" (With the only difference being that it executes itself).
For that reason, functions such as mysql_fetch_array (Or any MySQL/MySQLi function akin to that) cannot, and will not work. The software does not provide any form of built in alternatives either, effectively leaving the user to invent their own methods to achieve the same results. I know, pretty lame.
So, this is where I'm stuck. As you'd expect, all and any information you find on the Internet assumes you can use these MySQL & MySQLi functions. What I need, is an alternative method to grab one array from the results of a looped query per loop. I simply cannot come to any conclusion that actually works.
tl;dr I need to be able to (1) loop a query, (2) get the output from each loop as it's own array with it's own name, and (3), do so without the use of functions like mysql_fetch_array. The query itself does not actually matter, so don't focus on that. I know what do with the query.
I understand this is horrifically confusing, long, and complicated. I've been trudging through this mess for days - Close to the point of "cheating" and storing the data I'm trying to get here as raw code in the database. Bad practice, but sure as heck a lot easier on my aching mind.
I salute any brave soul who attempts to unravel this mess, good luck. If this is genuinely impossible, let me know so that I can send the software devs an angry letter. All I can guess is that they never considered that a case like mine would come up. Maybe this is much more simple then I make it to be, but regardless, I personally cannot come to an logical conclusion.
Additional note: I had to rewrite this twice due to some un explained error eliminating it. For the sake of my own sanity, I'm going to take a break after posting, so I may not be able to answer any follow up questions right away. Refer to the tl;dr for the simplest explanation of my need.
Sure you can do this , here ( assuming $post_ids is an array of post_id that you stated you had in the OP ), can I then assume that I could get category in a similar array with a similar query?
I don't see why you couldn't simply do this.
$post_id = array(49, 48, 47, 46, 43);
$result = array();
foreach($post_id as $id)
{
//without knowing the data returned i cant write exact code, what is returned?
$query = "SELECT category FROM post_categories WHERE post_id = $id";
$cats = fakeMarkup_executeQuery($query);
if(!empty($cats)) {
if(!isset($result[$id])){
$result[$id] = array();
}
foreach( $cats as $cat ){
$result[$id][] => $cat;
}
}
}
Output should be.
Array
(
[49] => Array
(
[0] => fifa
)
[46] => Array
(
[0] => sports
[1] => rio
[2] => dolphins
)
[43] => Array
(
[0] => puppies
[1] => trucks
)
)
Ok, assuming you can run a function (we'll call it find select) that accepts your query / ID and returns an array (list of rows) of associative arrays of column names to values (row), try this...
$post_categories = [];
foreach ($post_id as $id) {
$rows = select("SOME QUERY WHERE post_id = $id");
/*
for example, for $id = 46
$rows = [
['category' => 'sports'],
['category' => 'rio'],
['category' => 'dolphins']
];
*/
if ($rows) { // check for empty / no records found
$post_categories[$id] = array_map(function($row) {
return $row['category'];
}, $rows);
}
}
This will result in something like the following array...
Array
(
[49] => Array
(
[0] => fifa
)
[46] => Array
(
[0] => sports
[1] => rio
[2] => dolphins
)
[43] => Array
(
[0] => puppies
[1] => trucks
)
)
I would first like to thank you for taking the time to look at my question--I am quite novice at PHP/CodeIgniter programming, however, I enjoy it very much.
What I am trying to do:
1) Retrieve each CompanyId associated with the company when the user is logged in. I achieve this by passing the $CompanyId (in my controller) from the session as a parameter to a query in my model. I have this working well as such:
// Assign query result to array to be used in view
$data['campaigns'] = $this->model_record->retrieve_campaign($CompanyId);
2) The return value is an array nested as such:
Array (
[campaigns] => Array (
[0] => Array (
[CampaignId] => 1
[DID] => 2394434444
[FWDDID] => 3214822821
[ProductId] => 1
[CampaignName] => Fort Myers Bus #1
[ProductName] => CallTrack - Sharktek
[Active] => 1
[CompanyId] => 1 )
)
3) Once this is processed, I am trying to create a for each loop that queries each CampaignId through another query in my model. Due to the MVC pattern I am implementing, I have to pass the results of this query to my $data array to send to the view.
foreach($data['campaigns'] as $campaign) {
$ids[] = $campaign['CampaignId'];
}
foreach ($ids as $row) {
$data['ids'] = $this->model_record->week_data(0,$row, $StartDate);
}
4) I am then trying to test view all the results of my queries in my view, however, I am only receiving one value, but when I echo the results of the foreach of the CampaignIds, it they all show up. Does anyone have any suggestions?
<?php
foreach($ids as $row):
echo $ids['MyCount'];
endforeach
?>
5 Extra) I have not begun to approach this yet, but once I get this working, I would like to run the query week_data 7 times as it is returning the data for each day of the week. My assumption is that I would place a for loop until it hits 7, is this correct?
Thank you again, for attempting to help me--I greatly appreciate the work many of you put into this community.
This line:
$data['ids'] = $this->model_record->week_data(0,$row, $StartDate);
Should look like:
$data['ids'][] = $this->model_record->week_data(0,$row, $StartDate);
As it is, the first line overwrites $data['ids'] until all you're left with is the last one. You need to add them to an array to collect all of them.
So, here is the deal. I searched everywhere for the answer, but didn't find antyhing concrete ehough for my case, maybe i'm googling something wrong. Btw, i wanted phpmyadmin to be NOT in english, but it automatically changes back to cro... so... :/ hope you will understand enough to help me with solution...
Link to my table
TIP: I know how to get a solution through mysql, so you don't have to write those answers.
Here is the deal. This table is made by joining 2 other tables, because that was the only way to get all required data(that i must display) from one query (and that is relevant because later i will have to implement sort, which won't work otherwise).
I managed to pull out data which doesn't repeat itself with function, so this is what my solution looks by now:
1
tema1
opis1
sastanak.jpeg
2012-11-26 16:29:58
2012-11-26 17:30:00
2
tema2
opis2
sastanak.jpeg
2012-11-27 16:29:58
2012-11-29 18:30:00
3
tema3
opis3
sastanak.jpeg
2012-11-28 16:29:58
2012-11-28 17:05:00
4
tema4
opis4
sastanak.jpeg
2012-11-29 16:29:58
2013-11-29 21:42:00
and so on...
That's ok, but that is not all I need.
I'm still 2 steps away.
I need to count all id's, where current id is equal to previous. That means that solution would be:
5 (id_sastanka=1 appears 5 times in table)
5 (id_sastanka=2 appears 5 times),
6 (id_sastanka=3 appears 6 times),
6 (id_sastanka=4 appears 6 times) and so on.
I tried various combinations, but all give everything BUT correct result, so please help. I know the solution is in something simple, but I just can't seem to reach it. So this actually represents number of users who were invited to a meeting, by meeting's id.
I need to count all id's where status=1. I know how to do all of this with mysql, so that is not the question, I need the answer in php...
Solutions to this should be:
4 (four "1" in "status" where "id_sastanka"=1),
4 (four "1" in "status" where "id_sastanka"=2),
5 (five "1" in "status" where "id_sastanka"=3),
3 (three "1" in "status" where "id_sastanka"=4)....
this represents number of users who attended those meetings.
I'm a beginner, and I really need help with this, so I hope you won't bear a grudge.
I guess, that each row of your data represents as array. So, I'll write code for the following data structure:
$rows = array(
0 => array(
'id_sastanka' => 1,
'naziv' => 'tema1',
'opis' => 'opis1',
'slika' => 'sastanak.jpeg',
'posetak' => '<...>',
'zavrsetak' => '<...>',
'dnevny_red' => '<...>',
'id_korisnika' => '<...>',
'status' => '1'
),
1 => array(...),
2 => array(...),
...
);
$prev_id = null;
$prev_id_counter = array();
$ids_status_counter = array();
foreach($rows as $row) {
if ($prev_id == $row['id_sastanka']) {
$prev_id_counter[$row['id_sastanka']] = (isset($prev_id_counter[$row['id_sastanka']])) ? ++$prev_id_counter[$row['id_sastanka']] : 1;
}
$prev_id = $row['id_sastanka'];
if ($row['status'] == 1) {
$ids_status_counter[$row['id_sastanka']] = (isset($ids_status_counter[$row['id_sastanka']])) ? ++$ids_status_counetr[$row['id_sastanka']] : 1;
}
}
So, in array $prev_id_counter result for the first case and $ids_status_counter store result for the second one. Arrays have format ['id_sastanka'] => case counter
I have a table with various entries such as start date (contract), some random documents and monthly invoices and receipt in it, like this:
DOCUMENT TYPES
ID TYPE CHECK? MONTHLY?
1 Contract Yes No
2 Documents No No
3 Policy Yes No
4 Order No No
5 Invoice Yes Yes
6 Receipt Yes Yes
DOCUMENTS
ID TYPE DATE
1 1 01/01/2013
2 2 01/01/2013
3 3 01/01/2013
4 5 01/02/2013
5 6 01/02/2013
6 4 14/02/2013
7 5 01/03/2013
8 6 01/03/2013
TODAY 05/05/2013
My goal is to produce the output as shown below.
Display all existent documents, where CHECK? is Yes, and display missing documents where MONTHLY? is Yes.
01 Contract 01/01/2013 OK
02 Documents 01/01/2013 OK
03 Policy 01/01/2013 OK
04 Invoice 01/02/2013 OK
05 Receipt 01/02/2013 OK
06 Invoice 01/03/2013 OK
07 Receipt 01/03/2013 OK
08 Invoice 01/04/2013 Missing
09 Receipt 01/04/2013 Missing
10 Invoice 01/05/2013 Missing
11 Receipt 01/05/2013 Missing
I have written some code, but I not understand how to include monthly loop to display invoices and receipts.
QUERY
// Get type
$query = "SELECT * FROM doc_type
WHERE check='1'";
$result = mysql_query($query) or die(mysql_error());
$num = mysql_numrows($result);
// Get docs
$check = array();
$query2 = mysql_query("SELECT document_type_id FROM documents");
while ($row = mysql_fetch_assoc($query2)) {
$check[] = $row['document_type_id'];
WHILE
<tbody>
<?php
$i=0;
while ($i < $num) {
$document_type_id = mysql_result($result,$i,"document_type_id");
$document_type = mysql_result($result,$i,"document_type");
?>
<tr class="grade">
<td><?php echo $document_type_id; ?></td>
<td><?php echo $document_type; ?></td>
<td>
<?php
if (in_array($document_type_id, $check)) {
echo "<p style='color:green'>Ok</p>";
} else {
echo "<p style='color:red'>Miss</p>";
}
?>
</td>
</tr>
<?php
$i++;
}
?>
</tbody>
First, I must point out that I am slightly confused by the example data, because it looks like you are loading the data from a database for the first table, but the example implies that there is a list of documents that is being saved elsewhere for each job or project.
If it were me, I'd create either an object or an array representing your final table. That object you can then fill based on the available data. Given the data structure that you seem to be already using, I will assume that you would rather not use an Object Oriented Programming approach.
First, create an array or object that stores your original table information that matches the document type and the monthly setting. Once you choose a data format, you can load the data format from your database for each different group of settings. I will use the settings you have shown in your example.
Personally, I'd use the document type id as the index key and use boolean values to represent Yes (true) and No (false) like this:
$doc_requirements = array(
1 => array( "name" => "Contract", "check" => true, "monthly" => false ),
2 => array( "name" => "Documents", "check" => false, "monthly" => false ),
3 => array( "name" => "Policy", "check"=>true, "monthly"=>false ),
4 => array( "name" => "Order", "check"=>false, "monthly"=>false ),
5 => array( "name" => "Invoice", "check"=>true, "monthly"=>false ),
6 => array( "name" => "Receipt", "check"=>true, "monthly"=>false )
);
Use your database to store as many of these tables as you need and load them before reviewing your document list.
Next I would create an array that represents the output table. Index it by date so you can determine if you have missing documents. Your data implies that on each date, that we can have more than one document, but not more than one document of the same type, so you might be able to use something like this:
/* pseudo_code */ $temp_table = array(
[date] => array(
[doc_type_name] => array(
/* I assume that the document id is actually just the line number
on the table, so I will leave the id out of this, but if it is
not just the line on the table, add this field to the array:
"id" => [id], */
"status" => [status] )
),
[doc_type_name] => array(
"status" => [status] )
),
...
),
[date2] => array( ... ),
....
);
Load this array with the documents that you know about from your document array:
(note: you are using the mysql functions, which are currently deprecated, so you should look at using the msyqli functions instead)
$sql = #### /* SQL query string for your list of documents that are not missing */
$result = mysql_query($sql) or die(mysql_error());
if($result){
while( $document = mysql_fetch_assoc( $result ) ){
$date = $document[ "date" ];
$doc_type_id = $document[ "type_id" ];
$doc_type_name = $doc_requirements[ $doc_type_id ]["name"];
$temp_table[ $date ][ $doc_type_name ]["status"]= "OK"
/* we have the document, therefore, we know it is okay,
we can set that value immediately */
}
}
$start_date=#### /* set start date of contract */
$end_date=##### /*set end date of contract */
foreach( $doc_requirements as $requirement ){
if( $requirement["monthly"] == true ){
for( $cur_date = $start_date; $cur_date <= $end_date; $cur_date=#### ){
/*increment the date by whatever function you choose,
I recommend using a DateTime object
for your dates and incrementing by using the add() method */
$current_doc_name = $requirement[ "name"];
if( !isset( $temp_table[$cur_date][ $current_doc_name ] ) ){
/* if the array value is not set,
then a document of the type_name
and current date specified does not exist,
because the requirement for "monthly" == true,
we know that we should have it, so we will
set the status to "Missing" */
$temp_table[$cur_date][$current_doc_name]["status"] = "Missing";
}
}
}
}
Now we have an array organized by date, containing one document record for each document that we have a record of in our database (but no more than one of each type per date...If you need to change this, just change the data structure of the array to match your needs or use an object oriented approach that helps map out your thoughts more naturally). For any item that is Monthly = true (YES) we have a "Missing" stub created for it indicating that something was expected there but not found. Having this data array, we can cycle through it and produce the output.
I have noted above that your document id appears to just be the line number on the output table, so I will represent it the same way here:
$doc_id = 1;
foreach($temp_table as $cur_date){
foreach($cur_date as $doc_name){
$doc_id_string = your_func_format_id( $doc_id );
/* use whatever function you like to make your doc_id two digits.
Perhaps printf() would be useful */
$color_code = "style='color:green'";
if( $doc_name["status"]=="Missing" ) $color_code = "style='color:red'";
echo "<tr class='grade'><td>$doc_id_string</td><td>$doc_name</td><td>$cur_date</td><td><p $color_code>{$doc_name["status"]}</p></td>";
}
}
I have learned that using the correct data structure makes everything more simple. I have tried to use a data structure that reflects your example code. I highly recommend using Object Oriented Programming (OOP) techniques to implement your designs, because OOP forces every programmer to consider the shape of the data before considering the programming code, and it solves many problems.
EDIT::
Maybe I should be asking what the proper way to get a result set from the database is. When you have 5 joins where there is a 1:M relationship, do you go to the database 5 different times for the data??
I asked this question about an hour ago but haven't been able to get an answer that was fitting. I went ahead and wrote some code that does exactly what I need but am looking for a better way to do it
This array gives me multiple rows of which only some are needed once and others are needed many times. I need to filter these as I have done below but want a better way of doing this if possible.
Array
(
[0] => Array
(
[cid] => one line
[model] => one line
[mfgr] => one line
[color] => one line
[orderid] => one line
[product] => many lines
[location] => many lines
)
[1] => Array
(
.. repeats for as many rows as were found
)
)
This code works perfectly but again, I think there is a more efficient way of doing this. Is there a PHP function that will allow me to clean this up a bit?
// these are the two columns that produce more than 1 result.
$product = '';
$orderid = '';
foreach($res as $key)
{
// these produce many results but I only need one.
$cid = $key['cid'];
$model = $key['model'];
$mfgr = $key['mfgr'];
$color = $key['color'];
$orderid = $key['orderid'];
// these are the two columns that produce more than 1 result.
if($key['flag'] == 'product')
{
$product .= $key['content'];
}
if($key['flag'] == 'orderid')
{
$orderid .= $key['content'];
}
}
// my variables from above in string format:
Here is the requested SQL
SELECT
cid,
model,
mfgr,
color,
orderid,
product,
flag
FROM products Inner Join bluas ON products.cid = bluas.cid
WHERE bluas.cid = 332
ORDER BY bluas.location ASC
Without seeing your database structure it's a bit hard to decipher how you actually want to manipulate your data.
Perhaps this is what you're looking for though?
SELECT p.cid, p.model, p.mfgr, p.color, p.orderid, p.product, p.flag, GROUP_CONCAT(p.content SEPARATOR ', ')
FROM products AS p
INNER JOIN bluas AS b ON p.cid = b.cid
WHERE b.cid = 332
GROUP BY p.cid, p.flag
ORDER BY b.location ASC
So now for each product cid each flag will have an entry consisting of a comma separated list instead of there being many repeating for each flag entry.
Then after you're done with the string you can quickly turn it into an array for further manipulation by doing something like:
explode(', ', $key['content']);
Again it's really hard to tell what information you're trying to pull without seeing your database structure. Your SQL query also doesn't really match up with your code, like I don't even see you grabbing content.
At any rate I'm pretty sure some combination of GROUP BY and GROUP_CONCAT (more info) is what you're looking for.
If you can share more of your database structure and go into more detail of what information exactly you're trying to pull and how you want it formatted I can probably help you with the SQL if you need.