I'm just learning PHP and I've searched for a while on this, but I'm afraid I may not know exactly how to ask it, so an explanation will probably work best. Basically I have a group by/count query returning 3 records.
Status Total
0 2
1 3
2 2
On my page I would like to display:
Status Total
Dev 2
Active 3
Arch 2
So I basically just want to assign the values 0, 1 and 2 to a text value. I've tried creating an array, then assigning the return number field equal to the array.
$_status = array(0 => 'Development', 1 => 'Production', 2 => 'Archive');
while($rowStat = mysql_fetch_assoc($resDev))
{
echo "<tr><td>$_status[$rowStat['status']]</td><td>{$rowStat['devprojects']}</td></tr>";
};
Any help is much appreciated.
Thanks.
as you can see here http://php.net/mysql_fetch_assoc the field names are case sensitive
from what I see in your table sample the field is called "Status"
and you are using "status"
you can try changing
$rowStat['status']
to
$rowStat['Status']
Edit:
the initial version of the answer only focused on what's the problem (and suggested pdo)
I only want to add that I agree to two other optinions found here:
the one added via comment to this answer by giorgio: you should only use lowercase names for your database fields; also you should consider using the table name as a prefix (product_id instead or id, user_password instead of password) for two main reasons: to avoid colisions when you fetch results using a join and to avoit collisions with mysql reserved words (as id, password and status are)
the other one, suggested by Crashspeeder by a comment to the question: you definitely should develop with error reporting on and disable it on live servers
I don't really like using the 0, 1, 2 to represent a named value (unless you have a relational) table in your DB... but using your setup, why not just use:
while($rowStat = mysql_fetch_assoc($resDev)){
switch($rowStat['Status']){
case 0:
echo "<tr><td>Development</td><td>{$rowStat['devprojects']}</td></tr>";
break;
case 1:
echo "<tr><td>Production</td><td>{$rowStat['devprojects']}</td></tr>";
break;
case 2:
echo "<tr><td>Archive</td><td>{$rowStat['devprojects']}</td></tr>";
break;
}
};
EDIT
Some people really are looking for copy-paste answers so here's an updated answer because Sgt. Crashspeeder of the Massively Anal Society got her knickers in a twist.
Create a lookup array to reference against the status Ids:
$statusArray[0] = 'Development;
$statusArray[1] = 'Production;
$statusArray[2] = 'Archive;
Then when you're running your mysql_fetch_assoc() loop, you can reference the statusArray lookup like so:
while($rowStat = mysql_fetch_assoc($resDev)){
echo "<tr><td>{$statusArray[$rowStat['Status']]}</td><td>{$rowStat['devprojects']}</td></tr>";
}
Related
I am trying to do a search and return a single value. I am getting different results depending on how I try to get the value.
If the table has the following values:
id
name
1
Professional I
2
Professional II
3
Professional III
4
Professional IV
5
Teacher I
6
Teacher II
And I set $type = 4, I expect to get Professional IV.
CertificateRequest::find($type)->name;
Returns Professional VI which is what I want.
However,
CertificateRequest::find($type)->value("name"));
and
CertificateRequest::find($type)->first()->value("name");
Both return Professional I
What am I doing wrong? The problem with the first approach is if $type = null, I get Attempt to read property "name" on null. It also becomes harder to dynamically pass a column name.
This code should do what you want:
CertificateRequest::where('id', $type)->value("name"));
The difference is that find executes the query, which means that value seems to execute a second query without the type parameter. The where method modifies the query without executing it, allowing the value method to execute the query and return a result.
Use
CertificateRequest::findOrFail($type)->name;
Will return data or 404, not null.
You can try
$data = CertificateRequest::where('id',$type)->get();
EDIT
CertificateRequest::select($field)->where('id',$type);
Maybe this can help !
I am trying to get 5 questions per page with answers (one to many relational for questions and answers table) but, i am getting the number of records per page for this join table, is there anyway to limit the results based on questions table for pagination.
<?php
$topic_id = $_GET['topic_id'];
$answers_data = [];
$questions_data = [];
if (isset($_GET["page"])) { $page = $_GET["page"]; } else { $page=1; };
$num_rec_from_page = 5;
$start_from = ($page-1) * $num_rec_per_page;
$sql = "SELECT questions.q_id,questions.question,answers.answers,answers.answer_id FROM questions INNER JOIN answers ON questions.q_id = answers.q_id WHERE topic_id='$topic_id' LIMIT $start_from, $num_rec_from_page";
$result = $connection->query($sql);
while($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}//While loop
foreach($data as $key => $item) {
$answers_data[$item['q_id']][$item['answer_id']] = $item['answers'];
}
foreach($data as $key => $item) {
$questions_data[$item['q_id']] = $item['question'];
}
?>
I am get results for above query data using 2 for-each loops as below.
<?php
$question_count= 0;
foreach ($answers_data as $question_id => $answers_array) {
$question_count++;
$q_above_class = "<div class='uk-card-default uk-margin-bottom'><div class='uk-padding-small'><span class='uk-article-meta'>Question :".$question_count."</span><p>";
$q_below_class = "</p></span><div class='uk-padding-small'>";
echo $q_above_class.$questions_data[$question_id].$q_below_class;
$answer_count = 0;
foreach($answers_array as $key => $answer_options) {
$answer_count++;
$answer_options = strip_tags($answer_options, '<img>');
$ans_above_class="<a class='ansck'><p class='bdr_lite uk-padding-small'><span class='circle'>".$answer_count."</span>";
$ans_below_class = "</p></a>";
echo $ans_above_class.$answer_options.$ans_below_class;
}
echo "</div></div></div>";
}
?>
Is there any idea, how can i limit the results per page, based on questions table.
something like this
SELECT
q.q_id,
q.question,
a.answers,
a.answer_id
FROM
(
SELECT
q_id, question
FROM
questions
WHERE
topic_id=:topic_id
LIMIT
$start_from, $num_rec_from_page
) AS q
JOIN
answers AS a ON q.q_id = a.question_id
A few questions/thoughts/notes.
you had question.q_id and question.question_id which seems like an error. So I just went with q_id the other one is more typing (which I don't like) I had a 50-50 chance I figured... so
you had just topic_id so I can't be sure what table it's from, I'm assuming it's from table "question"? It makes a big difference as we really need the where condition on the sub-query where the limit is.
Inner Join, is the same thing as a Join, so I just put Join because I'm lazy. I found this previous post (click here) on SO that talks about it
:topic_id I parameterized your query, I don't do variable concatenation and SQLInjection vulnerability stuff. (aka. please use prepared statements) Named placeholders are for PDO, that's what I like using, you can pretty much just replace it with a ? for mysqli
as I said with INNER JOIN, I'm lazy so I like aliasing my tables with just 1 character, so that was what I did. ( I think you don't even need the AS part, but I'm not "that" lazy). Sometimes I have to use 2, which really irritates me, but whatever
With a sub-query, you can just limit the rows from that table, then you join the results of that query back to the main query like normal. This way you pull 5 or what have you from question table, and then {n} rows from answer based only on the join to the results of the inner query.
Cant really test it, but in theory it should work. You'll have to go though the results, and group them by question. Because you will get {n} rows that have the same 5 questions joined in them. With PDO, you could do PDO::FETCH_GROUP I don't think Mysqli has an equivalent method so you'll have to do it manually, but it's pretty trivial.
UPDATE
Here is a DB fiddle I put to gather you can see it does exactly what you need it to
https://www.db-fiddle.com/f/393uFotgJVPYxVgdF2Gy2V/3
Also I put a non-subquery below it to show the difference.
As for things like small syntax errors and table/column names, well I don't have access to your DB, you're going to have to put some effort in to adapt it to your setup. The only information I have is what you put in the question and so your question had the wrong table/column name. I already pointed several of these issues out before. I'm not saying that to be mean or condescending, it's just a blunt fact.
UPDATE1
Based on you comment. in 1st query the question is redundant
This is just the way the database works, To explain it is very simple, in my example I have 5 questions that match with 8 answers. In any database (not including NoSQL like mongoDB) you can't realistically nest data. In other words you cant pull it like this.
question1
answer1
answer2
answer3
You have to pull it flat, and the way that happens is like this
question1 answer1
question1 answer2
question1 answer3
This is just a natural consequence of how the Database works when joining data. Now that that is out of the way, what do we do about it. Because we want the data nested like in the first example.
We can pull the question, iterate (loop) over the result and do a query for each question and add the data to a sub-element.
Advantage It's easy to do
Disadvantage While this works it's undesirable because we will be making 6 connections to the database (1 to get 5 questions, 1 to get answers for each of the 5 questions), it requires 2 while loops to process the results, and actually more code.
Psudo code instructions (i don't feel like coding this)
init data variable
query for our 5 questions
while each questions as question
- add question to data
- query for answers that belong to question
- while each answers as answer
-- add answer to nested array in data[question]
return data
We can process the results and build the structure we want.
Advantage We can pull the data in one request
Disadvantage we have to write some code, in #1. we still have to write code, and in fact we have to write more code, because we have to process the DB results 6x (2 while loop) here we need 1 while loop.
Psudo code instructions (for comparison)
init data variable
query for our 5 questions and their answers
while each questions&answers as row
- check if question is in data
-- if no, add question with a key we can match to it
- remove data specific to question (redundant data)
- add answers to data[question]
return data
As you can see the basic instructions for the second one are no more complex then the first (same number of instruction). This is just assuming each line has the same complexity. Obviously a SQL query or a while loop is more complex then an if condition. You'll see below how I convert this psudo code to real code. I actually often write psudo code when planing a project.
Anyway, this is what we need to do. (using the previous SQL or the first one in the fiddle). Here is your normal "standard" loop to pull data from the DB
$data = [];
while($row = mysqli_fetch_assoc($result)) {
$data[] = $row;
}//While loop
We will modify this just a bit (it's very easy)
//query for our 5 questions and their answers(using SQL explained above)
//init data variable
$data = [];
//while each questions&answers as row
while($row = mysqli_fetch_assoc($result)) {
// - create a key based of the question id, for convenience
$key = 'question_'.$row['q_id'];
// - check if question is in data
if(!isset( $data[$key] ) ){
//--if no, add question with a key we can match to it
$data[$key] = [
'q_id' => $row['q_id'],
'question' => $row['question'],
'children' => [] //you can call this whatever you want, i choose "children" because there is a field named "answers"
];
}
//- remove data specific to question (redundant data) [optional]
unset($data['q_id'], $data['question']);
//- add answers to data[question]
$data[$key]['answers'][] = $row;
}
//return data
So what does this look like: For the first while, the standard one, we get this with as you called it redundant data.
[
["q_id" => "4", "question" => "four", "answers"=>"4", "answer_id"=>"4"],
["q_id" => "5", "question" => "five", "answers"=>"5", "answer_id"=>"5"],
["q_id" => "5", "question" => "five", "answers"=>"5", "answer_id"=>"6"],
]
For the second one, with our harder code (that's not really hard) we get this:
[
["q_id" => "4","question" => "four","children" = ["answers"=>"4","answer_id"=>"4"]],
[
"q_id" => "5",
"question" => "five",
"children" = [
"answers"=>"5",
"answer_id"=>"5"
],[
"answers"=>"5",
"answer_id"=>"6"
]
],
]
I expanded the second question so you can see the nesting. This is also a good example of why it had redundant data, and what is happening in general. As you can see there is no way to represent 8 rows with 5 shared question without have some redundant data (without nesting them).
The last thing I would like to mention is my choice of $key. We could have used just q_id with no question_ bit added on. I do this for 2 reasons.
It's easier to read when printing it out.
There are several array_* (and other) functions in PHP that will reset numeric keys. Because we are storing important data here, we don't want to lose that information. The way to do this is to use strings. You can just cast it to a string (int)$row['q_id'], but in some cases the keys can still get removed. An example is when JSON encoding, there is a flag JSON_FORCE_OBJECT that forces numeric keys to be an object {"0":"value} but it acts global. In any case it can happen where you lose the keys if they are just numbers, and I don't much care for that happening. So I prefix them to prevent that.
It's not hard to do something like preg_match('/question_([0-9]+)/', $key, $match) or $id = substr($key, 9); to pull it back off of there,We have the q_id in the array,It's no harder to check isset($data['question_1']) then isset($data['1']), and it looks better.
So for minimum difficulty we can be sure we won't lose our ID's to some code over site (unless we use usort instead of uasort) but I digress..
I have an ENUM stored in PHPMYADMIN which allows the numbers 1-10.
I'm trying to find out how that number can be converted to a string which the user can see, an example is;
1=London
2=Spain
3=France
4=Germany
etc...
The obvious way would be to do an if statement for each something like
if ENUM == 1 then STRING == "London"
if ENUM == 2 then STRING == "Spain"
but I was wondering if there was a similar way of doing this or if I just need to do 10 if statements. I've tried to look online but no helpful tutorials.
Thanks (Sorry i've had to submit the question as code, stackoverflow wouldnt allow me to post it otherwise for some reason)
Here is an efficient/clean/professional way of doing it:
$enum = 1; // The value fetched from the database
$cities = array(
'1'=>'London',
'2'=>'Spain',
'3'=>'France',
'4'=>'Germany'
); // Array of cities
// Make sure there is a city with the given key
if(isset($cities[$enum])){
echo $cities[$enum];
}
But it is also advisable to store the cities in another database table.
I'm new to web design, especially backend design so I have a few questions about implementing a search function in PHP. I already set up a MySQL connection but I don't know how to access specific rows in the MySQL table. Also is the similar text function implemented correctly considering I want to return results that are nearly the same as the search term? Right now, I can only return results that are the exact same or it gives "no result." For example, if I search "tex" it would return results containing "text"? I realize that there are a lot of mistakes in my coding and logic, so please help if possible. Event is the name of the row I am trying to access.
$input = $_POST["searchevent"];
while ($events = mysql_fetch_row($Event)) {
$eventname = $events[1];
$eventid = $events[0];
$diff = similar_text($input, $event, $hold)
if ($hold == '100') {
echo $eventname;
break;
else
echo "no result";
}
Thank you.
I've noticed some of the comments mentioned more efficient ways of performing the search than with the "similar text" function, if I were to use the LIKE function, how would it be implemented?
A couple of different ways of doing this:
The faster one (performance wise) is:
select * FROM Table where keyword LIKE '%value%'
The trick in this one is the placement of the % which is a wildcard, saying either search everything that ends or begins with this value.
A more flexible but (slightly) slower one could be the REGEXP function:
Select * FROM Table WHERE keyword REGEXP 'value'
This is using the power of regular expressions, so you could get as elaborate as you wanted with it. However, leaving as above gives you a "poor man's Google" of sorts, allowing the search to be bits and pieces of overall fields.
The sticky part comes in if you're trying to search names. For example, either would find the name "smith" if you searched SMI. However, neither would find "Jon Smith" if there was a first and last name field separated. So, you'd have to do some concatenation for the search to find either Jon OR Smith OR Jon Smith OR Smith, Jon. It can really snowball from there.
Of course, if you're doing some sort of advanced search, you'll have to condition your query accordingly. So, for instance, if you wanted to search first, last, address, then your query would have to test for each:
SELECT * FROM table WHERE first LIKE '%value%' OR last LIKE '%value%' OR address LIKE '%value'
Look at below example :
$word2compare = "stupid";
$words = array(
'stupid',
'stu and pid',
'hello',
'foobar',
'stpid',
'upid',
'stuuupid',
'sstuuupiiid',
);
while(list($id, $str) = each($words)){
similar_text($str, $word2compare, $percent);
if($percent > 90) // Change percentage value to 80,70,60 and see changes
print "Comparing '$word2compare' with '$str': ";
}
You can check with $percent parameter for how strong match you want to apply.
Basically, i have a working form where the user inputs details about their laptop to sell to my shop.
I give them a quote once they have submitted the Specs of the laptop.
At the moment i have got option boxes and checkboxes which each have a value-- for example these. ---
<label for="state">State</label><br>
<select name="state">
<option value="10">Excellent</option>
<option value="5">Good</option>
<option value="0">Poor</option>
</select><br>
The Values of the options they have selected get added up at the end and that gives them the quote - in the above example - "10" means £10 extra for a excellent condition laptop etc.
I use $_POST[state] to get the value of it to add onto the other options for the quote.
But my problem lies when i POST them to a database (so we can check when they come in).
When they get added to the database, obviously it just comes out as the values not the actually name of it like "excellent" or "good". just says "10" or "5".
Is there anyway to put the name of the option into the database instead of the value?
sure... just make sure that's what you want to do. It's usually not considered a good database practice to create denormalized tables like that, but you could do it. When you collect your post data, simply create another variable and assign a value to it based off the state value like so:
$stateText = '';
switch ($state){
case 10:
$stateText = 'Excellent';
break;
case 5:
$stateText = 'Good';
break;
case 0:
$stateText = 'Poor';
break;
default:
// bad value
$stateText = '';
}
...then store this to the database in a new column.
This is just one of many ways to do this.
You can only do it if you have a lookup, be it an array or in another table that stores the keys and values.
You should be carefuly not to store the post data directly into your database without sanitizing it, otherwise you might become subject to sql injection.
Is there anyway to put the name of the option into the database instead of the value?
There is, but it involves doing it explicitly (converting "10" into "Excellent" before inserting the value) rather than just basically tossing $_POST into the database as-is. You can make this very simple if you are building the <option>s with an array in the first place by reading the the array again and swapping the values with the keys.
$values = array(
10 => 'Excellent',
5 => 'Good',
0 => 'Poor',
);
$post_value = $_POST['state'];
$db_value = $values[$post_value];
// further validation: make sure the array key exists or use a default value
// further usage: build your HTML <options> with this array
However:
If you're going to do that, you're much better off storing the values as numbers and converting them to words when you display them (assuming the numbers do have some meaning). This also allows you to localize by providing translations.
Response to comments:
I would recommend a rating system, like 1 through 5, and calculate your price modifications internally - not directly from the user input or from a hardcoded value (in the database). This allows you to tweak the price changes from within your app, rather than from database values that were created at an earlier time, like if you decide an "Excellent" condition warrants an increase of 11 rather than 10 - unless you specifically want the prices "locked in" permanently at the time the product was posted.
Whatever you do, make sure to validate the input - I can't think of any good reason to use direct user input to calculate prices - it should be done internally based on product ids, and any other conditions. HTML source can be modified on-the-fly to post values you didn't expect from the dropdown.
You can't get it via the HTML form. But you can still do a server side that would map the values to the appropriate condition.
You can use a switch statement or an if statement to map them.
if(value == 10){
$condition = 'Excellent';
} else {//....}