I have been racking my brains over this for a while now. Here is the data I have in the SQL data base as an example:
ID | TYPE | DATA
1 | TXT | TEST
2 | PHP | php
3 | JS | JAVASCRIPT
That is just an example, there are multiple listing for TXT, PHP and JS throughout the table. What I want to do is retrive all the data and display it all into separate drop down/select boxes. Meaning, select box one would list all data with type TXT, select box two would list all data with type PHP and select box 3 would list all data with type JS. The only way I have came about doing this is doing individual sql queries for each different type. I know there is a way to do it all in 1 query and then display it the way I want to but I just can't seem to figure out how and I know its going to drive me nuts when someone helps and I see just how they did it.
The only way that I know of to get all of the data in one query is just to do a generic SELECT * FROM tbl, and then you can group them in the code:
$res = mysqli_query('SELECT * FROM tbl');
$data = array();
while($row = mysql_fetch_assoc($res)) {
$type = $row['type'];
$data[$type][] = $row;
}
// $data contains all of the record, grouped by the TYPE column
foreach($data as $type => $records) {
echo "records for $type: <select>";
foreach($records as $record) {
echo "<option value='$id'>$id</option>";
}
echo "</select>";
}
Just retrieve all records and loop through them using PHP. Use an iterator if the recordset is going to be huge to prevent using too much memory.
$lists = array();
foreach($recordset as $record) {
$lists[$record['type']][$record['id']] = $record['data'];
}
Know you have an array containing all data.
Just order it by Type and make a loop using "foreach" into the results, changing of select box when the type is different than the preivous.
In this way you only loop once over the array.
You can do kind of grouping with "ORDER BY TYPE":
SELECT id, data
FROM table
ORDER BY type;
Then, in data output loop you can track current type, and build another select box once type changed:
$currentType = "no type";
while($row = mysql_fetch_assoc($res)) {
if ($currentType != $row['type']) {
$currentType = $row['type'];
// start new select box here
}
// do some other work here
}
BTW, such approach looks like kind of hack :)
Related
I am trying to combine the results from 2 queries into a single array but am having problems getting the correct code.
I have a table called PrimaryEvents that I query to add to an array. This query works ok:
$rows = query("SELECT * FROM PrimaryEvents WHERE unit = ? ORDER BY event", $unit);
I add the data to an array using the following:
foreach ($rows as $row)
{
// $event = lookup($row["event"]); (removed as spotted by sergio not required)
$event["event"] = $row["event"];
$event["validity"] = $row["validity"];
$event["eventsrequired"] = $row["eventsrequired"];
$event["unit"] = $row["unit"];
$event["role"] = $row["role"];
//now we have the data lets try and do something to it
if ($event["role"] == "0")
{
//then the user is active so change value to a YES
$event["role"] = "ALL";
}
//add our stock to the portfolio array
$portfolio[] = $event;
}
So far everything works well. I would like to query a separate table and add certain results to the array portfolio[];
$rowsCompleted = query("SELECT * FROM portfolio WHERE id = ? ORDER BY name", $_SESSION["id"]);
My original plan was to use the following additional code to add the data of interest to the portfolio[] but it doesn't work:
//now add individual stats to the array
foreach($rowsCompleted as $row)
{
if ($portfolio["event"] == $row["name"]
{
//then add our number and date to the array
$portfolio["datecompleted"] = $row["datecompleted"];
$portfolio["number"] = $row["number"];
}
//else do nothing
}
My final aim was to pull the datacompleted value and number value from the portfolio table and then add it to the array ONLY if the event name matches the name in portfolio array.
Hopefully I have described my problem and required behaviour well enough.
Thanks for nay help that can be offered, I am new to php/sql so learning as I go.
Andy
EDIT:
Also tried the following loop to try and loop through the array:
//now add individual stats to the array
foreach($rowsCompleted as $row)
{
foreach ($portfolio["event"] as $item)
{
if ($portfolio["event"] == $row["name"]
{
//then add our number and date to the array
$portfolio["datecompleted"] = $row["datecompleted"];
$portfolio["number"] = $row["number"];
}
}
//else do nothing
}
EDIT2: To try and make my question more clear: The Primary-events table lists all the events a specific user has to complete. The portfolio table tracks which events have been completed by the user (by means of date-completed and number).
I want to run a query that lists all the events from Primary-events, then into those results add the date-completed and number from the users portfolio. If the answer is blank from the portfolio then the user has not yet completed the event but I would still like to list it from the Primary-events table data.
I tried 2 queries to start with as it seemed to follow what I was trying to achieve.
EDIT3:
New code with help from Barmar
foreach ($rows as $row) {
$event = lookup($row["event"]);
$event["event"] = $row["event"];
$event["validity"] = $row["validity"];
// $event["datecompleted"] = $row["datecompleted"];
// $event["number"] = $row["number"];
$event["eventsrequired"] = $row["eventsrequired"];
$event["unit"] = $row["unit"];
$event["role"] = $row["role"];
//now we have the data lets try and do something to it
if ($event["role"] == "0") {
//then the user is active so change value to a YES
$event["role"] = "ALL";
}
//add our stock to the portfolio array
$portfolio[] = $event;
//now add individual stats to the array
foreach ($rowsCompleted as $row) {
foreach ($portfolio as &$item) {
if ($item["event"] == $row["name"]) {
//then add our number and date to the array
$item["datecompleted"] = $row["datecompleted"];
$item["number"] = $row["number"];
}
}
}
}
The page still isn't being displayed by chrome so guessing i've missed something.
EDIT4: Page displayed, I am now getting undefined index errors when the table is rendered on the html page.
Specifically the undefined index errors are for date-completed and number. I am taking it to mean that these values are not being added to the portfolio array? Do try and help I have added an Else statement (as below) to ensure that even if the event isn't available the index is:
//now add individual stats to the array
foreach($rowsCompleted as $row)
{
foreach ($portfolio as &$item)
{
if ($item["event"] == $row["name"])
{
//then add our number and date to the array
$item["datecompleted"] = $row["datecompleted"];
$item["number"] = $row["number"];
}
else
{
$item["datecompleted"] = "Never";
$item["number"] = "0";
}
}
}
EDIT 5: Near Success. Sorry to reopen this but I have just noticed behaviour I wasn't expecting: The nested loop only sets the date-completed and number for the first value to matches from the portfolio table. The follow on values are not set. It would seem like the nested loop isn't stepping through all of the portfolio values, and just exiting once the first "event" == "name".
EDIT 6: Sample data and clarification on desired functions:
portfolio sample data
|id|name |number|datacompleted
|21|event1 |3 |2014-07-07
|15|event1 |5 |2014-07-05
|21|event2 |5 |2014-05-08
|15|event1 |1 |2013-05-05
id is the id of the user that completed the event
number is the number of events completed
PrimaryEvents sample data
|id|event |validity|eventsrequired
|1 |event1 |7 |10
|1 |event2 |25 |1
|1 |event3 |12 |50
id is the id of the user that created the entry (used for historic purpose only)
The desired functionality is:
The query should create a an array to allow a html table to be created of everything within the Primary-events table. This table lists the events the user must complete.
The second query or current nested loop should gather the data from the portfolio table for the current user id, then match the event name to the name in the Primary-events array and update (if present) the number and date-completed value. (I.E populate the data for the events that the user has completed).
The current code merges the data from portfolio only for the first match, but then the nested loop seems to exit.
Hopefully this is a more clear description of what I am trying to achieve.
EDIT: I have changed the functionality to use the Left join statement below but am still having problems:
The table only contains some of the events from primary-events table and not all of them. The events being pulled over are only those that the user has completed, the ones the user has not yet completed are not being shown.
EDIT: This query seems to work:
$allEvents = query("SELECT * FROM PrimaryEvents LEFT JOIN portfolio ON (PrimaryEvents.event = portfolio.name) WHERE PrimaryEvents.event = ? AND (portfolio.id = ? Or portfolio.id is null) ORDER BY PrimaryEvents.event", $currentEvent, $_SESSION["id"]);
You need to notice that portfolio is not associative array but multidimensional array, so you cannot access it using $portfolio["event"]. You should use $portfolio[0]["event"], $portfolio[1]["event"] and so on.
It's hard to show you exact solution because I don't know how those arrays/database queries should be merged.
EDIT
It seems your query should look like this:
query("SELECT * FROM PrimaryEvents e LEFT JOIN portfolio p ON e.event = p.name WHERE e.unit = ? AND p.id = ? ORDER BY e.event", $unit,$_SESSION["id"]);
EDIT2
I haven't proposed nested loop (as it's now in modified question) because of performance loss.
You're getting closer with your second query, but still confused about what's in each array.
foreach($rowsCompleted as $row)
{
foreach ($portfolio as &$item) // Need to use reference so we can update it
{
if ($item["event"] == $row["name"])
{
//then add our number and date to the array
$item["datecompleted"] = $row["datecompleted"];
$item["number"] = $row["number"];
break;
}
}
}
To avoid the nested loop, it would be better for $portfolio to be an associative array. Change the code for your initial query to use:
//add our stock to the portfolio array
$portfolio[$event["name"]] = $event;
Then the second loop becomes:
foreach($rowsCompleted as $row)
{
$name = $row["name"];
if (isset($portfolio[$name]) {
$portfolio[$name]["datecompleted"] = $row["datecompleted"];
$portfolio[$name]["number"] = $row["number"];
}
}
I have e.g. the following data returned from a query, each name is an item:
id name comment
1 FF hey
1 FF hey back!
2 LL
3 PP i think its great!
3 PP me too
3 PP I'm not sure
4 TT
5 II
6 KK yesterday is the new tomorrow
When I display it, each 'item' has an id and are displayed in DIVs use LI.
As you can see though there are multiple comments sometimes for an 'item', each on a separate line
What I want to do is display each item and then show comments under each item if there are any. So, i can't group by anything at query stage as the comment section is unique, but need to group at display stage
So currently have:
while ($row = mysql_fetch_array($result)){
echo '<li><div class=className><div class=itemName>'.$row[name].'</div>';
if($row[comment]){
echo '<div class=newRow>'.$row[comment].'</div>';
}
echo '</div></li>';
}
Now, this is no good because this will produce multiple displays for the same item with one comment under each.
Can I do this or should I bring in the data differently?
The ideal result is e.g.
FF LL PP etc etc etc
hey i think its great!
hey back! me too
I'm not sure
You can use GROUP_CONCAT() on your mysql query to group all the comments together for each name
SELECT id, name
GROUP_CONCAT(comment) AS comment
FROM table
GROUP BY name;
then explode() the $row[comment] in your php code
while ($row = mysql_fetch_array($result)){
echo '<li><div class=className><div class=itemName>'.$row['name'].'</div>';
if($row['comment'] != ""){
$comments = explode(",",$row['comment']);
foreach($comments as $comment){
echo '<div class=newRow>'.$comment.'</div>';
}
}
echo '</div></li>';
}
Edit
Thanks to #CBroe, I now know that GROUP_CONCAT() has a group_concat_max_len default of 1024. You will want to increase this before running the GROUP_CONCAT() query -
SET [GLOBAL | SESSION] group_concat_max_len = 10240; // must be in multiples of 1024
SELECT id, name
GROUP_CONCAT(comment) AS comment
FROM table
GROUP BY name;
you will also need to be aware of max_allowed_packet as this is the limit you can set var_group_concat_max_len to.
note: mysql_query() does not allow multiple queries, so you will need to do 2 mysql_query(), and you can use SET SESSION ... so that all queries in your current session have that max_len. It would be better to change from mysql_ functions (which are depreciated) and change to mysqli_ or PDO as they offer multiple query option. also check out - http://php.net/manual/en/mysqlinfo.api.choosing.php
Don't confuse data access with output and you will have an easier time attacking this sort of problem.
//Fetch and Sort
$data = array();
while ($row = mysql_fetch_array($result)){
$item = $row['item'];
if(!isset($data[$item]) {
$data[$item] = array():
}
$data[ = $data[$item][] = $row['comment'];
}
//Output
foreach($data as $item => $comments) {
echo '<li><div class=className><div class=itemName>'.$item.'</div>';
foreach($comments as $comment) {
echo '<div class=newRow>'.$comment.'</div>';
}
echo '</div></li>';
}
If you are not getting the data back sorted by id already, add to the end of your query:
ORDER BY name
which will retrieve the same list ordered by id. Then in your while loop, add a variable that keeps track of the last item name that you saw. If it changes, add a new li, otherwise, add the comment on to the end of your current list.
Say I have a query the following query run:
Edit
Added order clause because the real sql statement has one.
SELECT description, amount, id FROM table ORDER BY id
In this instance, the ID is not unique to the dataset. It would return something like this.
Description Amount ID
----------- ------ --
1 Hats 45 1
2 Pants 16 1
3 Shoes 3 1
4 Dogs 5 2
5 Cats 6 2
6 Waffles 99 3
What I need to do is enclose each section of IDs in it's own div (So rows 1,2,3 in one div, 4,5 in another div and 6 in it's own div).
There are tons of solutions to this but I just can't think of one that isn't overly complicated.
I want to be able to keep the SQL how it is and somehow sort the data set in PHP so that I can loop through each section of the dataset while looping through the dataset as a whole.
Some kind of array would work but the structure of it is stumping me.
How can I get this to work? PHP solutions would be idea but theoretical will help too.
See if something like this works for you.
// execute query: Select description, amount, id from table
$results = array();
while ($row = $query_result->fetch_array()) {
if (!isset($results[$row['id']])) $results[$row['id']] = array();
$results[$row['id']][] = $row; // push $row to results for this id
}
// later on
foreach($results as $id => $data) {
// output div based on $id
foreach($data as $datum) {
// output individual data item that belongs to $id
}
}
A simple serial solution might look something like this:
$curId = ''; // track working id
$firstDiv = true; // track if inside first div
// open first div
echo '<div>';
// foreach $row
{
// when id changes, transition to new div, except when in first div
if ($row->$id != $curId) {
if ($firstDiv) {
$firstDiv = false;
} else {
// start new div
echo '</div>';
echo '<div>';
}
$curId = $row->$id; // track new current id
}
// display contents of current row
}
// close last div
echo '</div>';
Just store the id in temp variable, if the next one is different close the div and open new div
Assuming associative arrays for the db results:
$final = array();
foreach($results as $result)
{
$final[$result['id']][] = $result;
}
This leaves you with an associative array $final that groups the entries by ID
I'm failing miserably to get my head around what I know ought to be simple, and am unsure if the solution lies in the query or in processing the result, so struggling to search for what I'm sure has been covered in another post.
I'm working with a single MySQL table, from which I need to be able to retrieve and process content that shares a common ID. Unfortunately, restructuring the database isn't an option.
Here's what a simple SELECT * WHERE contentID = '2' query returns:
|contentType|contentID|content |
--------------------------------------
|title |2 |<h1>title</h1>|
|intro |2 |<p>intro</p> |
|main |2 |<p>main</p> |
What's the correct way to retrieve the specific 'title', 'intro' or 'main' content?
Thanks in advance.
$result = mysql_query("SELECT * WHERE contentID = '2'");
$array = array();
while($rows = mysql_fetch_array($result,MYSQLI_ASSOC)){
$array[$rows['contentType']] = $rows['content'];
}
You can use the $array for each content type
Fetch all the rows into an array:
$data = array();
foreach ($rows as $r) {
$data[$r['contentType']] = $r['content'];
}
You'd have to put your content type into the where clause. The Id and type should form a natural ok and should be constrained as such. If not, time to redesign. Also, id consider putting the content type as a lookup rather than a string.
<?php
function executeQuery($query,$connectionObject)
{
queryString=$query;
recordSet=mysql_query(queryString,$connectionObject);
if(!$recordSet)
{
$errorString=mysql_error($this->connectionObject);
return array("error"=>$errorString);
}
return recordSet;
}
function getNextRecord($recordSet)
{
$resultArray =mysql_fetch_assoc($recordSet);
if(!empty($resultArray))
return($resultArray);
else
return "false";
}
$result = executeQuery("SELECT * FROM foo WHERE contentID = '2'");
$nextRecord = getNextRecord($result);
while($nextRecord!="false")
{
$nextRecord = getNextRecord($result);
//...........Process the record.....
->$nextRecord['contentType'];
->$nextRecord['contentID'];
->$nextRecord['content'];
//..................................
}
I have a database with the following table:
id value
-----------
1 yes
2 no
3 no
4 maybe
I'm using some simple php to log the choices entered on a poll website. The user selects a radio box and it is entered into the above table. However, I want to make this a little more flexible. I created a simple backend that allowed an admin user to add or delete poll choices. What would I do to show on the frontend the number of votes for each individual choice, when the number of choices is not constant? I know I could do this easily if the poll choices were static but since the backend user will be changing the choices, how could I dynamically display the results?
I am not really sure what you are asking. Is it COUNT you're looking for?
Don't worry about the choices or the number of choices, grab all the votes/choices and iterate through them and add them to an array indiscriminately: http://codepad.org/LWPyuTqj
$total = array();
$votes = array(1=>'yes',2=>'no',3=>'no',4=>'maybe');
foreach($votes as $vote) {
if (!isset($total[$vote]))
$total[$vote] = 1;
else
$total[$vote] += 1;
}
print_r($total);
I would recommend google graph API for this. It is really easy!
http://code.google.com/apis/chart/interactive/docs/gallery/piechart.html
Generate the code dynamically, using the first example on the link above. First select the values. This assuming there is a question ID so you can relate to the question. In this case id 1.
$result = mysql_query('SELECT value,COUNT(*) as num FROM choises WHERE question_id = 1 GROUP BY value');
Then with PHP loop through the data
$results = array();
while ($row = mysql_fetch_assoc($result)){
$results[$row['value']] = $num;
}
With this you can generate the graph:
echo 'data.addRows('.count($results).');';
$i = 0;
foreach ($results as $value => $num){
echo'
data.setValue('.$i.', 0, "'.$value.'");
data.setValue('.$i.', 1, '.$num.');
';
$i++;
}