Here is my database:
id | liker | ques_id
1 | 15 | 2342
2 | 22 | 2342
3 | 22 | 2311
4 | 15 | 2389
What I need to get is all the liker's who have liked ques_id. So the result should look something like this:
Question 2342 has been liked by 15 and 22.
Question 2311 has been liked by 22 and so on
My current code produces separate row for each liker and ques_id:
$sqlq=mysql_query("SELECT * FROM likes");
while($rowq=mysql_fetch_array($sqlq)){
$qid=$rowq['ques_id'];
$sql=mysql_query("SELECT * FROM likes where ques_id='$qid'");
$num=mysql_num_rows($sql);
$cont='';
while($row=mysql_fetch_array($sql)){
$liker=$row['liker'];
$cont .="$qid being liked by $liker<br>";
}
echo $cont;
}
I haven't tested this but it should get you started:
$sqlq=mysql_query("SELECT DISTINCT(ques_id) FROM likes");
$cont='';
while($rowq=mysql_fetch_array($sqlq)){
$qid=$rowq['ques_id'];
$sql=mysql_query("SELECT * FROM likes where ques_id='$qid'");
$num=mysql_num_rows($sql);
$row=mysql_fetch_array($sql)
$cont .= "$qid being liked by $liker ";
while($row=mysql_fetch_array($sql)){
$liker=$row['liker'];
$cont .= " and $liker";
}
$cont .= ".<br>";
}
echo $cont;
You need no second query to DB, it enough iterate only first result.
For example, you may collect all the likers, that match a specific ques_id in a assoc array with keys are ques_id, like this:
$mathces = array();
$sqlq=mysql_query("SELECT * FROM likes");
while($rowq=mysql_fetch_array($sqlq)){
$qid=$rowq['ques_id'];
$liker=$rowq['liker'];
$matches[ $qid ][] = $liker;
}
Then, you may foreach $mathces array and build you string.
foreach ($matches as $qid => $likers) {
$cont .= "$qid being liked by " . implode(' and ', $likers );
if (count($likers) == 1)
$cont .= ' and so on';
echo "$cont<br>";
}
I didn't test my code. It need to additional validations (e.g. for $linkers in second loop)
SELECT GROUP_CONCAT(liker), ques_id FROM likes GROUP BY ques_id
That will pull each liker grouped together for each ques_id.
You then only have to process the rows returned.
You should steer clear of the mysql extension as it is deprecated; use PDO or mysqli instead.
$sql = 'SELECT GROUP_CONCAT(liker) as likes, ques_id FROM likes GROUP BY ques_id';
foreach ($conn->query($sql) as $row) {
printf('Question %s is liked by %s', $row['ques_id'], $row['likes']);
}
Related
First loop table
user_id | fname | lname
1 | first | emp
2 | second| emp
3 | third | emp
Second loop table
shift_id | employee_id
1 | 1
2 | 2
3 | 2
if($employees)
{
foreach ($employees as $employee)
{
if($employee['user_id'] == $shift['employee_id'])
{
echo ucwords($employee['fname']. ' ' .$employee['lname']);
}
}
}
I am getting the right result but I think there is some better way of writing this.
You can use joins in table. Left join means that the user line has to exists (because: LEFT) and the shifts enty is optional.
SELECT user.user_id, user.fname, user.lname, shifts.shift_id
FROM yourUserTable AS user
LEFT JOIN yourShiftsTable AS shifts ON(user.user_id = shifts.employee_id)
Now you get it in your initial array, as if you'd select it as one row from a table and no longer need to do tricks in PHP to combine information. If you can, always try to get the database to manage data, it does that way faster than PHP can.
Please note, the query could be a little off, I just wrote this out of the top of my head.
Just some test code I whipped up to test this from the information provided for this "Demonstration Code".
Note: I have used the mysqli class for the database (instantiating $db ) and have excluded the SQL Table setup.
What you would have had is something along the lines of this...
Case 1 - The original
$db = new mysqli('localhost', 'root', 'test', 'phptutorials_st26');
echo '<h2>Create $employees </h2>';
$query = "SELECT * FROM users";
$result = $db->query($query);
$employees = $result->fetch_all(MYSQL_ASSOC);
var_dump($employees);
echo '<h2>Create $shifts </h2>';
$query = "SELECT * FROM shifts";
$result = $db->query($query);
$shifts = $result->fetch_all(MYSQL_ASSOC);
var_dump($shifts);
echo '<h2>Using foreach on $employees and $shifts</h2>';
if ($employees) {
foreach ($employees as $employee) {
foreach ($shifts as $shift) {
if ($employee['user_id'] == $shift['employee_id']) {
echo ucwords($employee['fname'] . ' ' . $employee['lname']);
echo '<br>';
}
}
}
}
The Result from the above is
First Emp
Second Emp
Second Emp
Case 2 - Using a Join
Well using a join, as everyone has already stated, is the way to go...
$sql = "SELECT u.user_id, u.fname, u.lname, s.shift_id
FROM users AS u
JOIN shifts AS s ON(u.user_id = s.employee_id)
";
$result = $db->query($sql);
$employees = $result->fetch_all(MYSQL_ASSOC);
// To see what comes out because we always check things.
var_dump($joined_result);
(Don't ask me why I love using very abbreviated aliases for the table names! It's just "a thing".)
Then your "loop" simply becomes...
echo '<h2>Using foreach on join</h2>';
foreach ($employees as $employee) {
echo ucwords($employee['fname'] . ' ' . $employee['lname']);
echo '<br>';
}
And the result is...
First Emp
Second Emp
Second Emp
Case 2 - has reduced the code and only requires 1 Trip to the Database.
Does that help you any?
You could do it this way also. Its a little shorter.
SELECT TABLE1.FNAME, TABLE1.LNAME, TABLE2.EMPLOYEE_ID
FROM TABLE1, TABLE2
WHERE TABLE1.USER_ID = TABLE2.EMPLOYEE_ID;
I am a newbie to PHP and I am stuck at a certain point. I tried looking up a solution for it however, I didn't find exactly what I need.
My goal is to create a leaderboard, in which the values are displayed in descending order plus the rank and score are displayed. Furthermore, it should also display whether or not a tie is present.
The database should look like this:
+---------+------+----------------+-------+------+
| user_id | name | email | score | tied |
+---------+------+----------------+-------+------+
| 1 | SB | sb#gmail.com | 1 | 0 |
+---------+------+----------------+-------+------+
| 2 | AS | as#web.de | 2 | 0 |
+---------+------+----------------+-------+------+
| 3 | BR | br#yahoo.com | 5 | 1 |
+---------+------+----------------+-------+------+
| 4 | PJ | pj#gmail.com | 5 | 1 |
+---------+------+----------------+-------+------+
And the outputted table should look something like this:
+------+-------------+-------+------+
| rank | participant | score | tied |
+------+-------------+-------+------+
| 1 | BR | 5 | Yes |
+------+-------------+-------+------+
| 2 | PJ | 5 | Yes |
+------+-------------+-------+------+
| 3 | AS | 2 | No |
+------+-------------+-------+------+
| 4 | SB | 1 | No |
+------+-------------+-------+------+
I managed to display the rank, participant and the score in the right order. However, I can't bring the tied column to work in the way I want it to. It should change the value, whenever two rows (don't) have the same value.
The table is constructed by creating the <table> and the <thead> in usual html but the <tbody> is created by requiring a php file that creates the table content dynamically.
As one can see in the createTable code I tried to solve this problem by comparing the current row to the previous one. However, this approach only ended in me getting a syntax error. My thought on that would be that I cannot use a php variable in a SQL Query, moreover my knowledge doesn't exceed far enough to fix the problem myself. I didn't find a solution for that by researching as well.
My other concern with that approach would be that it doesn't check all values against all values. It only checks one to the previous one, so it doesn't compare the first one with the third one for example.
My question would be how I could accomplish the task with my approach or, if my approach was completely wrong, how I could come to a solution on another route.
index.php
<table class="table table-hover" id="test">
<thead>
<tr>
<th>Rank</th>
<th>Participant</th>
<th>Score</th>
<th>Tied</th>
</tr>
</thead>
<tbody>
<?php
require("./php/createTable.php");
?>
</tbody>
</table>
createTable.php
<?php
// Connection
$conn = new mysqli('localhost', 'root', '', 'ax');
if ($conn->connect_error) {
die("Connection failed: " . $conn->connect_error);
}
// SQL Query
$sql = "SELECT * FROM names ORDER BY score DESC";
$result = $conn->query("$sql");
// Initalizing of variables
$count = 1;
$previous = '';
while($row = mysqli_fetch_array($result)) {
$current = $row['score'];
$index = $result['user_id']
if ($current == $previous) {
$update = "UPDATE names SET tied=0 WHERE user_id=$index";
$conn->query($update);
}
$previous = $current;
?>
<tr>
<td>
<?php
echo $count;
$count++;
?>
</td>
<td><?php echo $row['name'];?></td>
<td><?php echo $row['score'];?></td>
<td>
<?php
if ($row['tied'] == 0) {
echo 'No';
} else{
echo 'Yes';
}
?>
</td>
</tr>
<?php
}
?>
I think the problem is here
$index = $result['user_id'];
it should be
$index = $row['user_id'];
after updating tied you should retrieve it again from database
So I solved my question by myself, by coming up with a different approach.
First of all I deleted this part:
$current = $row['score'];
$index = $result['user_id']
if ($current == $previous) {
$update = "UPDATE names SET tied=0 WHERE user_id=$index";
$conn->query($update);
}
$previous = $current;
and the previous variable.
My new approach saves the whole table in a new array, gets the duplicate values with the array_count_values() method, proceeds to get the keys with the array_keys() method and updates the database via a SQL Query.
This is the code for the changed part:
// SQL Query
$sql = "SELECT * FROM names ORDER BY score DESC";
$result = $conn->query("$sql");
$query = "SELECT * FROM names ORDER BY score DESC";
$sol = $conn->query("$query");
// initalizing of variables
$count = 1;
$data = array();
// inputs table into an array
while($rows = mysqli_fetch_array($sol)) {
$data[$rows['user_id']] = $rows['score'];
}
// -- Tied Column Sort --
// counts duplicates
$cnt_array = array_count_values($data);
// sets true (1) or false (0) in helper-array ($dup)
$dup = array();
foreach($cnt_array as $key=>$val){
if($val == 1){
$dup[$key] = 0;
}
else{
$dup[$key] = 1;
}
}
// gets keys of duplicates (array_keys()) and updates database accordingly ($update query)
foreach($dup as $key => $val){
if ($val == 1) {
$temp = array_keys($data, $key);
foreach($temp as $k => $v){
$update = "UPDATE names SET tied=1 WHERE user_id=$v";
$conn->query($update);
}
} else{
$temp = array_keys($data, $k);
foreach($temp as $k => $v){
$update = "UPDATE names SET tied=0 WHERE user_id=$v";
$conn->query($update);
}
}
}
Thank you all for answering and helping me get to the solution.
instead of the update code you've got use something simular
$query = "select score, count(*) as c from names group by score having c > 1";
then you will have the scores which have a tie, update the records with these scores and your done. Make sure to set tie to 0 at first for all rows and then run this solution
UPDATE for an even faster solution sql based:
First reset the database:
$update = "UPDATE names SET tied=0";
$conn->query($update);
All records have a tied = 0 value now. Next update all the records which have a tie
$update = "update docs set tied = 1 where score IN (
select score from docs
group by score having count(*) > 1)";
$conn->query($update);
All records with a tie now have tied = 1 as we select all scores which have two or more records and update all the records with those scores.
I am trying to fetch data from my database and would like to group common values in the column called order_ids by that id.
This is the state I currently get my data in
Order_Id | Product Name
-------------------------------
10001 | iPhone 5
10001 | Blackberry 9900
10002 | Galaxy S
10003 | Rhyme
10004 | Google Nexus
10005 | Razr
10006 | iPad Air
And this is the state I want to get it in
Order_Id | Product Name
-------------------------------
10001 | iPhone 5
Blackberry 9900
10002 | Galaxy S
10003 | Rhyme
10004 | Google Nexus
10005 | Razr
10006 | iPad Air
Here is how I get the result in my controller file
foreach($results_query as $results_custom) {
$this->data['result_custom'][] = array(
'model' => $results_custom['product_name'],
'order_number' => $results_custom['order_id']
);
}
Here is how I display it in my view file
<?php foreach ($results_custom as $result) { ?>
<li><?php echo $result['model']; ?></li> <br />
<li><?php echo $result['order_number']; ?></li><br />
<?php } ?>
Is it possible to get my data to display like that or in that state by using SQL or PHP? Please let me know if you want to see my query as well.
In php would be easier to do it. As I don't have PHP enviroment to test it I will show you some logic to do it. Not necessarily working code. Thats because you didn't provide what you did
<?
$sql = "select order_id, product name from ..... order by order_id"// rest of sql code ....
//here you iterate your results
$previousId = ""; //var to store previous id
while( $fetch... ){
if ( $fetchedID != $previousId ){
echo $fetchedId . "-" . $fetchedProductName;
}else{
echo $fetchedProductName;
}
$previousId = $fetchedID;
}
?>
This should do.
As you updated your code this is a solution for you:
<?php
$lines = ""; //to make code cleaner;
$previousModel = "";
foreach ($results_custom as $result) {
if ( $previousModel != $result['model'] ){
$line .= "<li>" . $result['model'] . "</li>";
}else{
$line .= "<li></li>";
}
$line .= "<li>" . $result['model'] . "</li><br />";
$previousModel = $result['model'];
}
echo $line;
<?php } ?>
I suggest you to use GROUP_CONCAT for getting the result
You try as follows
SELECT order_id,GROUP_CONCAT(product_name) as product_name FROM your_table GROUP BY order_id
Just look at this http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
Note : GROUP_CONCAT has a size limit. Check this link for more MySQL and GROUP_CONCAT() maximum length
you might be able to accomplish this in just MySQL, but it might be easier if you just create a php loop. most people prefer a foreach loop, but I like while loops:
$orderid = "number";
$order_query = mysql_query("SELECT * FROM ordertable WHERE Order_Id = '$orderid'");
while($order_data = mysql_fetch_array($order_query)){
$ordername = stripslashes(mysql_real_escape_string($order_data['Product Name']));
echo $ordername.'<br />';
}
if you need this for ALL orders you could remove searching for a specific order:
$order_query = mysql_query("SELECT * FROM ordertable ORDER BY Order_Id ASC");
while($order_data = mysql_fetch_array($order_query)){
$orderid = mysql_real_escape_string($order_data['Order_Id']);
$ordername = stripslashes(mysql_real_escape_string($order_data['Product Name']));
echo 'ID#: '.$orderid.' - '.$ordername.'<br />';
}
I want to get Name and corresponding Score at the latest time. So I tried:
$queryObj = mysql_query("SELECT `Name`,`Score` from `Table`.`Score` where `Date` = ( SELECT max(`Date`) from `Table`.`Score`) and `Name`<>'' ");
then get value from it by:
while( $obj = mysql_fetch_object( $queryObj ) ) {
$data = array();
$data['Name'] = $obj->Name;
$data['Score'] = $obj->Score;
$searches[] = $data;
}
But when I print :
print_r(array_values($searches));
the first value is missing in the array, so that won't be the right way.
I also tried:
$row = mysql_fetch_assoc($queryObj);
for ($i = 0; $i <3; $i++)
print( $row['Name'][$i]." Score: ".$row['Score'][$i]."<br />\n");
But it won't give me the right results also. How do I get the value from that query? (the query is correct, I tested it). Any body has suggestion ?
Edit: I add my sample data here:
Name Score Date
abc 3 2013-08-29 10:11:47
abc 2 2013-08-29 09:39:23
abc 1 2013-08-28 10:22:28
jane 2 2013-08-29 09:39:23
2013-08-29 10:08:36
jane 1 2013-08-29 10:11:47
tarzan 1 2013-08-29 10:11:47
Note: Yes, there is some blank values.
My expected result would be:
abc score 3
jane score 1
tarzan score 1
Ok, so after you have updated your question and provided what you expect, your query should look like this:
SELECT t1.Name, t1.Score
FROM Table.Score t1
INNER JOIN
(
SELECT max(Date) MaxDate, Name, Score
FROM Table.Score
WHERE Name <> ''
GROUP BY Name
) t2
ON t1.Name = t2.Name AND t1.Date = t2.MaxDate
This will give you pairs of Name and Score for each Name with Score based on his latest Date (1 row per Name).
So replace your original query with mine in this line:
$queryObj = mysql_query(" ... ");
Then:
$rows = array();
while($row = mysql_fetch_assoc($queryObj)) {
$rows[$row['Name']] = $row['Score'];
}
And you can nicely foreach it in the exact way you wanted in your last comment:
foreach($rows as $name => $score) {
echo $name . ' - ' . $score . "\n";
}
I have two tables, who are joined and the ID of each table and element underneath are similar.
parentID | objectName | subID ID| className| subName |
_____________________________ ________________________
84 | Test | 14 14| BOM | Test
84 | More | 16 14| PDF | Test
84 | Sub | 15 15| Schematics | Test2
I want to list the categoryname and the subID of the related elements. Several ObjectNames will have several related classes.
PHP code:
$objects = mysqli_query($con,"SELECT * from subobject");
$join = mysqli_query($con, "SELECT * FROM subrelation AS subrelation INNER JOIN subobject AS subobject ON subobject.subId = subrelation.ID;");
echo "<ul>";
while($obj = mysqli_fetch_array($objects) and $row = mysqli_fetch_array($join))
{
echo "<li>". $obj['objectName'];
echo "<ul>";
//ITERATION GOES HERE
if($obj['objectName'] == $row['subName'])
echo "<li>". "$row[className]" . "</li>";
//END OF ITTERATION
echo "</ul>";
echo "</li>";
}
echo "</ul>";
?>
and output list:
-Test
-BOM
-Sub
-Schematics
-More
under each field there are supposed to be more listed values.
It looks like you need to simplify your code a bit. My guess is that your problem is occurring because you have different amounts of rows in each result set. This makes your while loop exit when it finishes going through the smaller result set (probably $objects), even though there's still more elements in the larger set.
A solution is to sort the results of your query, use just one condition in your while loop, and keep track of which objectName you're currently on using a string $curr_objectName:
$join = mysqli_query($con, 'SELECT * FROM subrelation AS subrelation INNER JOIN subobject AS subobject ON subobject.subId = subrelation.ID ORDER BY subobject.objectName;');
$curr_objectName = '';
echo '<ul>';
while($row = mysqli_fetch_array($join)) {
$subName = $row['subName'];
if($subName != $curr_objectName)) {
if($curr_objectName != '') {
#close the previous list
#will be skipped on the first loop iteration
echo '</ul>';
echo '</li>';
}
#start a new list
$curr_objectName = $subName;
echo '<li>'. $obj['objectName'];
echo '<ul>';
} else {
echo '<li>'. $row['className'] . '</li>';
}
}
echo '</ul>';