How to get the right output from this SELECT query? - php

I have a query like so:
SELECT * FROM `purchases` p
JOIN `purchase_types` pt ON p.purchase_type = pt.node
When I run it in PHPmyAdmin it returns the proper result set like so:
node | purchase_type | amount_spent | node | name
--------------------------------------------------
2 | 5 | 8.5000 | 5 | Lunch
3 | 5 | 1.5000 | 5 | Lunch
4 | 6 | 4.6600 | 6 | Dinner
This is my PHP code:
$sql = "SELECT * FROM `purchases` p
JOIN `purchase_types` pt ON p.purchase_type = pt.node";
$query = mysql_query($sql);
$result = mysql_fetch_assoc($query);
$purchases = array();
while($row = mysql_fetch_assoc($query)) {
$purchases[] = array(
'name' => $row['name'],
'amount_spent' => $row['amount_spent']
);
}
for eaching over $expenses returns the following output:
3 | 5 | 1.5000 | 5 | Lunch
4 | 6 | 4.6600 | 6 | Dinner
What happens to the first "Lunch"? How can I have the PHP output be the same as the direct MySQL query output?

You call mysql_fetch_accoc before while. Don't.
You should also realize that ext/mysql will be deprecated and upgrade your code to use properly parameterized queries with PDO or mysqli

try with mysql_fetch_array,
$purchases = array();
while($row = mysql_fetch_array($query)) {
$purchases[] = $row;
}
if you want to get data just do
foreach($purchases as $key => $value)
{
$name = $value['name'];
$amount_spent = $value['amount_spent'];
echo 'name : '.$name.' , amount spent '.$amount_spent.'<br />';
}

Related

php database queries in foreach and optimization

I am creating a multilingual website and I want to display a different data for each country.
So i already had created script which determines the language and origin of the user and I need to load data from 3 databases on the website in foreach function.
I had 3 database
listFrom, listFromCountryCode, listFromLang
listFrom:
id, prefix, status
listFromCountryCode:
id, idList, countryCode, status,
listFromTranslate:
id, idList, name, langCode, status
currently, to get this data I need to do a loop for listFromCountryCode and listFrom to get prefix. I came up with some optimizations such as use INNER JOIN in query. I cant connect these database in one piece because prefix for other countries is the same. I haven't done this code yet because at the beginning I wanted to ask more experienced developers for advice on how to optimize it. I know that the use of a loop for database queries is bad but I have no idea for another solution.
Update
Already created script and time-tested so when in table is more elements (100) site loaded in 3s. Normal script without that script loaded in 0.46s. Anyone got any idea how to optimize this script?
public function checkCountryCodeList()
{
$sql = "SELECT COUNT(*) FROM listFromCountryCode WHERE countryCode = :code AND status = :status";
$array = array(':code' => $this->countryCode, ':status' => $this->status);
$result = $this->db->selectCount($sql, $array);
if($result > 0){
return true;
}else{
return false;
}
}
public function getCountryCodeList()
{
$sql = "SELECT idList
FROM listFromCountryCode
WHERE countryCode = :code";
$array = array(':code' => $this->countryCode);
$result = $this->db->select($sql, $array);
return $result;
}
public function getList()
{
if(!$this->checkCountryCodeList()){
$this->countryCode = DEFAULT_COUNTRYCODE;
}
$countryCodeList = $this->getCountryCodeList();
$data = array();
foreach($countryCodeList as $row){
$sql = "SELECT listFrom.prefix, listFromTranslation.name
FROM listFrom, listFromTranslation
WHERE listFrom.id = listFromTranslation.idList
AND listFrom.id = :id
And listFromTranslation.langCode = :code";
$array = array(
':id' => $row['idList'],
':code' => $this->langCode
);
$result = $this->db->select($sql, $array);
$data[] = ['name' => $result[0]['name'], 'prefix' => $result[0]['prefix']];
}
return $data;
}
Update
Some example data
listFrom
| id | prefix |status |
|--- | ------ |-------|
| 1 | btc |1 |
| 2 | psc |1 |
listFromCountryCode
| id | idList |countryCode |status |
|--- | ------ |------------|------ |
| 1 | 1 |de |1 |
| 2 | 2 |de |1 |
listFromTranslate
| id | idList| name |langCode |status |
|--- | ------| ----------- |---------|------ |
| 1 | 1 | bitcoin |en |1 |
| 2 | 2 | paysafecard |en |1 |

Join tables horizontally and dynamically

I need some help from joining tables horizontally my tables are
+---------+---------+
| Candidates Table |
+---------+---------+
| can_id | Name |
+---------+---------+
| 1 | Liza |
| 2 | Sarah |
| 3 | Jane |
| | |
+---------+---------+
+---------+---------+
| Judges Table |
+---------+---------+
| id | Name |
+---------+---------+
| 1 | judge1 |
| 2 | judge2 |
| 3 | judge3 |
+-------------------+
+---------+---------------+--------+-------+
| Score Table |
+---------+-------+------------------------|
| sco_id | can_id| jud_id |crit_id |score|
+---------+--------+-----------------------+
| 1 | 1 | 2 | 1 | 87 |
| 2 | 1 | 3 | 1 | 89 |
| 3 | 1 | 1 | 1 | 80 |
+------------------------------------------+
I need an output of something like this one..
+---------+---------------+-------------+
| Score board |
+---------+---------+-------------------|
| Name | judge1 | judge2 | judge3 |
+---------+---------+-------------------|
| Liza | 80 | 87 | 89 |
|some data|some data|some data|some data|
|some data|some data|some data|some data|
+---------------------------------------+
notes: crit_id is criteria id from criteria table.
Normally I would use some joins and subqueries but my problems is I need the output dynamically where in if I add a new judges it will automatically generate a new column. I need at least 1 candidate data with all of the judges scores then just loop it with parameters on php to get the other candidates data something like
php loop start
<td>name</td>
<td>judge1 score</td>
<td>judge2 score</td>
php end loop
or if i could get the whole candidates table with judges score much better for me not to loop them per candidate
I've tried to research similar questions like
Concatenate more than two tables horizontally in SQL Server
I've tried to code myself but I got stuck with joining the judges..
SELECT s.sco_id,c.Name,c.Municipalities
FROM `tbl_scoring` s
LEFT JOIN tbl_candidates c ON c.`can_id` = s.`can_id`
WHERE s.can_id = 11
AND crit_id = 1
ORDER BY s.jud_id asc
I need a query that would generate dynamically depending on the number of judges either get candidate data with scores of judge then loop it on php or much way better if i get all the data without looping
Initialize the following arrays:
$judges = [];
$scores = [];
$candidates = [];
Then execute your query, and loop the results. Set those values for each iteration:
$judges[$row['jud_id']] = 1;
$candidates[$row['can_id']] = $row['Name'];
$scores[$row['can_id']][$row['jud_id']] = $row['score'];
Now you want to get the participant judges names, so let's run a SQL query:
$sql = 'SELECT Name FROM judges WHERE id IN (' . implode(',', array_keys($judges)) . ')';
And on every iteration set the judge's name in the $judges array:
$judges[$row['id']] = $row['Name'];
Then for the output:
echo '<tr>';
echo '<td>Name</td>';
ksort($judges);
foreach ($judges as $name) {
echo '<td>Judge: ' . $name . '</td>';
}
echo '</tr>';
foreach ($scores as $candidateId => $data) {
echo '<tr>';
echo "<td>$candidates[$candidateId]</td>";
ksort($data);
foreach ($data as $score) {
echo "<td>$score</td>";
}
echo '</tr>';
}
I used ksort on $judges and $data so the score will fit each judge.
first, we retrieve the judges' ids and name that exist on the score table.
$judges = [];
$query = "SELECT id, name FROM Judges WHERE id IN ( SELECT DISTINCT jud_id FROM Score )";
// execute the query and store the results in the $judges array.
we retrieve the candidates' ids and name that exist on the score table.
$candidates = [];
$query = "SELECT id FROM Candidate WHERE id IN ( SELECT DISTINCT can_id FROM Score )";
// execute the query and store the results in the $candidates array.
then, we join the candidate and score table.
$candidate_score = [];
$query = "SELECT Candidate.name, Candidate.id as candidate_id , Score.jud_id, Score.score FROM Candidate JOIN Score ON Score.can_id = Candidate.id";
// execute the query and store it in the $candidate_score array.
now, for each candidate, we fill its score on the $score_board array.
$score_board = [];
foreach ( $candidates as $candidat )
{
$score_board[$candidat] = [];
foreach ( $judges as $judge )
{
$judge_name = $judge['name'];
$judge_id = $judge['id'];
$score_board[$candidat][$judge_name] = get_judge_score($candidate_score,$candidat,$judge_id);
}
}
this is how the get_judge_score will work:
function get_judge_score ( $scores , $candidate , $judge )
{
$score_filtred = array_filter($scores, function ($score) use ($candidate,$judge) {
return $score['jud_id'] == $judge && $score['candidate_id'] = $candidate;
});
return count($score_filtred) > 0 ? $score_filtred[0]['score'] : 0;
}

How to fetch results in while loop

I have the following 2 tables.
| ID | Name | Category |
|----|-------------|----------|
| 1 | Foo bar | 3 |
| 2 | Bar foo | 2 |
| 3 | Baz Foo | 3 |
| 4 | Baz Foo2 | 1 |
| 5 | Baz Foo3 | 1 |
| 3 | Baz Foo | 1 |
| ID | Category_name |
|----|---------------|
| 1 | Cat 111 |
| 2 | Cat 222 |
| 3 | Cat 3333 |
I want to display all categories with counter, example:
Cat111 - 3
Cat222 - 2
Cat333 - 2
I tried to do it by the following way, but its not working:
$query = mysqli_query('SELECT * FROM gallery');
while($row = mysqli_fetch_assoc($query)) {
$query_cat = mysqli_query($conn, "SELECT * FROM `pics_cat` WHERE id = '".$row['category']."' GROUP BY category_name");
$rowCat = mysqli_fetch_assoc($query_cat);
echo $rowCat['category_name'];
echo $rowCat['cnt'];
}
You are not sharing the names of the tables, but I assume the first one is Gallery and the second one is pics_cat
If your tables are not going to be very large, I suggest you to solve everything with a single join query, which simplifies the logic of your script.
$query = mysqli_query($conn, 'SELECT p.Category_name,COUNT(g.ID) AS cnt FROM `gallery` AS g LEFT JOIN `pics_cat` AS p ON p.ID = g.Category GROUP BY p.ID');
while($row = mysqli_fetch_assoc($query)) {
echo $rowCat['Category_name'];
echo $rowCat['cnt'];
}
If you prefer to do this with 2 queries in a loop, it's much easier to start from the Category table and then move to the gallery
$query = mysqli_query($conn, 'SELECT * FROM `pics_cat` ORDER BY ID');
while($row = mysqli_fetch_assoc($query)) {
$query_count = mysqli_query('SELECT COUNT(ID) AS cnt FROM `gallery` WHERE Category = '.$row['ID'].'');
$row_count = mysqli_fetch_assoc($query_count);
echo $row['Category_name'];
echo $row_count['cnt'];
}

How to query based on multiple relations between columns - MySQL?

I have four columns in a properties table: property_id, value, id, material_id.
I also have an array of properties: Array $properties
The schema is a bit complicated, because I want to find the material_id based on the matching properties.
An example:
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
Example table output:
+----+-------------+-------------+-------+
| id | material_id | property_id | value |
+----+-------------+-------------+-------+
| 1 | 1 | 3 | 5 |
| 2 | 1 | 3 | 5 |
| 3 | 1 | 3 | 5 |
| 4 | 2 | 1 | 3 |
| 5 | 2 | 2 | 6 |
| 6 | 2 | 3 | 4 |
| 10 | 4 | 1 | 9 |
| 11 | 4 | 2 | 3 |
| 12 | 4 | 3 | 6 |
+----+-------------+-------------+-------+
Now, I need material_id that satisfies all the properties. How can I do that..? Do I need to use exist statement of MySQL?
Now, for each element in your array you will want to run a statement that looks like this:
SELECT material_id FROM properties WHERE property_id = 2 AND value = 3;
Do you need help on the php code also? You could run a for each loop, but I will need to know what way you are using to communicate with your database for more specifics.
edit
foreach ($properties as $foo => $bar)
{
$sql = 'SELECT material_id FROM properties WHERE ';
foreach ($bar as $key => $value)
{
$sql .= $key .' = '. $value .' AND ';
}
$sql .= 'true';
*run your PDO code on $sql here*
}
On behalf of performance, it's not a good idea to run a query per array's value. If you have an oversized array things can get pretty slower.
So, best solution can be to build a single query including all conditions presented on $properties array:
<?php
$properties = array(['property_id'=>1,'value'=>3],['property_id'=>2,'value'=>6],['property_id'=>3,'value'=>4]);
$qCondition = [];
foreach($properties as $prop) {
$q = sprintf("(property_id = %d AND value = %d)", $prop["property_id"], $prop["value"]);
$qCondition[] = $q;
}
// assuming that your database table name is 'materials'
$sql = sprintf("SELECT * FROM materials WHERE (" . implode(" OR ", $qCondition) . ")");
echo $sql;
Result:
SELECT * FROM materials
WHERE ((property_id = 1 AND value = 3) OR (property_id = 2 AND value = 6) OR (property_id = 3 AND value = 4))
Therefore, you need to run only one single query to get all desired rows.
You can play with suggested solution here: http://ideone.com/kaE4sw

Get data and insert it using loop (MSQL/I)

I select data from table A and what I want is to insert that data using a loop.
Here's my code:
$getlvls = "SELECT * FROM `access_chart` WHERE `ac_id`='$data->ac_id'";
$qry99 = $con->query($getlvls);
while($row = $qry99->fetch_assoc()) {
$lvl1 = $row['lvl1'];
$lvl2 = $row['lvl2'];
$lvl3 = $row['lvl3'];
$lvl4 = $row['lvl4'];
}
for($jaa = 1; $jaa <=4; $jaa++){
$auth_id = '$lvl'+$jaa;
$sql1 = "INSERT INTO `overtime_log`(`ot_id`, `lvl`, `user_id`) VALUES('$ot_id', $jaa, '$auth_id')";
$qry = $con->query($sql1);
}
I don't include all of my codes. Everything works, except for inserting the column $lvl1, $lvl2, $lvl3 and $lvl4 using a loop. Or if you would suggest other logic that's find.
Thanks in advance.
EDITED
Select the data:
|----------------|
|--access_chart--| TABLE
|----------------|
-------------------
|---------|---------------|--------|--------|--------|--------|
|--ac_id--|--access_name--|--lvl1--|--lvl2--|--lvl3--|--lvl4--|
|---------|---------------|--------|--------|--------|--------|
| 1 | MIS Dept | 4 | 5 | 9 | 0 |
This might be the output after INSERT QUERY:
|----------------|
|--overtime_log--| TABLE
|----------------|
-------------------
|---------|-------|-----------|
|--ot_id--|--lvl--|--user_id--|
|---------|-------|-----------|
| 1 | 1 | 4 |
| 1 | 2 | 5 |
| 1 | 3 | 9 |
| 1 | 4 | 0 |
Not sure where $ot_id is defined, but assuming you're using only ids and SQL injection isn't a concern, you could use something like:
$getlvls = "SELECT * FROM `access_chart` WHERE `ac_id`='$data->ac_id'";
$qry99 = $con->query($getlvls);
while($row = $qry99->fetch_array())
{
foreach(array(1=>$row['lvl1'],2=>$row['lvl2'],3=>$row['lvl3'],4=>$row['lvl4']) as $key=>$lvl)
{
$sql1 = "INSERT INTO `overtime_log`(`ot_id`, `lvl`, `user_id`) VALUES('$ot_id', $key, '$lvl')";
$qry = $con->query($sql1);
}
}
Alternatively you could avoid the inner loop altogether and just write the INSERT using multiple-insert syntax:
$getlvls = "SELECT * FROM `access_chart` WHERE `ac_id`='$data->ac_id'";
$qry99 = $con->query($getlvls);
while($row = $qry99->fetch_array())
{
$con->query("INSERT INTO `overtime_log`(`ot_id`, `lvl`, `user_id`)
VALUES('$ot_id', 1, '{$row['lvl1']}'),
('$ot_id', 2, '{$row['lvl2']}'),
('$ot_id', 3, '{$row['lvl3']}'),
('$ot_id', 4, '{$row['lvl4']}')");
}

Categories