Sum query not working properly properly sql and php - php

Why this query instead of displaying the sum of points for each user, it display the sum of all together
I have written an SQL query that displays the sum of all point for all users, whereas I would like it to: display the sum of points for each user.
The table that I have written contains the following:
id | Score
1 | 20
2 | 30
2 | 50
1 | 10
Total table :
id | points
1 | 30
1 | 40
What I want is to add the score for user(1) = 30 and user(2) = 80
Id: 1 = 30 = Fail
Id: 2 = 80 = Pass
The query I have written :
$query = "SELECT SUM(sg.score) as sum, SUM(a.total) as suma FROM points as sg, totalpoints as a
WHERE a.id = 1 GROUP BY sg.id";
And related PHP code is as follows:
<?php
foreach($rowsum as $rowsm):
if( ' '. htmlentities($rowsm['sum']) . '' > 50 )
echo 'Pass';
else if( ' '. htmlentities($rowsm['sum']) . '' >= 40 )
echo 'Failed';
echo ' ' . htmlentities($rowsm['sum'], ENT_QUOTES, 'UTF-8') . '<br>';
endforeach;
?>

You need to group by the users ID:
SELECT SUM(score) as sum FROM points GROUP BY id ORDER BY id
You also have an incorrect WHERE clause
WHERE id=id
isn't needed.

I guess you should look forward using the GROUP BY clause :
SELECT
SUM(score) AS sum
FROM
points
GROUP BY
id
ORDER BY
id

You've omitted the GROUP BY clause:
$query = "SELECT SUM(score) as `sum` FROM points GROUP BY id ORDER BY id";
Your WHERE clause wasn't needed.

You need to do group by as below and it will give you the sum of scores for each user
SELECT SUM(score) as sum FROM points
group by id
ORDER BY id
If you need to find it for a specific user just add a where condition as
SELECT SUM(score) as sum FROM points
where id = 1
The above will give the sum of scores for id = 1 and can change for other values as needed.

Related

How to join and sum a column in two tables based on another column using mysqli and php (just using query)

I have 2 tables about blood bank:
donates
orders
in donates table I have 2 fields showing how many donations we have:
------------------------
| blood_group | amount |
------------------------
| A+ | 2 |
| B- | 3 |
| O+ | 4 |
| A+ | 3 |
| O+ | 1 |
in orders table I have 2 column that how many requests we submit based on blood group:
------------------------
| blood_group | amount |
------------------------
| A+ | 4 |
| B- | 3 |
| O+ | 4 |
| AB- | 6 |
My problem is I want to use mysqli query to get an array that show me this result based on these conditions:
show how many we need group by blood_group
if we don't need any blood_group or we don't have any request for that blood type show zero (not showing null)
not showing negative number for our blood shortage
I manage to do this so far:
<?php
$con = mysqli_connect("localhost", "root", "", "test");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}
$sql ="SELECT donates.blood_group as blood_group,
donates.amount as donates_amount,
orders.amount as orders_amount,
FROM `donates`
LEFT JOIN `orders`
ON donates.blood_group = orders.blood_group
GROUP BY donates.blood_group";
// Perform queries
$result = mysqli_query($con, $sql);
if (!$result = mysqli_query($con, $sql)) {
echo "SQLSTATE error: " . mysqli_sqlstate($con);
echo "<br>";
echo "SQLSTATE error: " . mysqli_error($con);
exit;
}
$result = mysqli_fetch_all($result, MYSQLI_ASSOC);
var_dump($result);
mysqli_close($con);
That query shows me sum of blood_groups but here is the main question:
So here are the main questions:
how to subtract (donates_amount and orders_amount)
how to make them positive (subtract which one first)
how to show the result even if one blood group is not presented on the other (full join)
Use union all and group by:
select blood_group, sum(donate_amount) as donate_amount,
sum(order_amount) as order_amount
from ((select blood_group, amount as donate_amount, 0 as order_amount
from donates
) union all
(select blood_group, 0 as donate_amount, amount as order_amount
from orders
)
) od
group by blood_group;
The only caveat is that a blood group needs to be in one of the tables. If you have a separate table of all of them, you should use that. For instance:
select bg.*,
coalesce(donate_amount, 0) as donate_amount,
coalesce(order_amount, 0) as order_amount
from blood_groups bg left join
(select blood_group, sum(amount) as donate_amount
from donates
group by blood_group
) d
on d.blood_group = bg.blood_group left join
(select blood_group, sum(amount) as order_amount
from donates
group by blood_group
) o
on o.blood_group = bg.blood_group ;
In either of these queries, you can get the difference using - and show negative numbers as 0 using greatest(). For instance:
greatest(sum(donate_amount) - sum(order_amount), 0)
To answer your first question :
how to subtract (donates_amount and orders_amount)
You must use SUM() function with a minus sign:
SUM(donates.amount - orders.amount);
this will subtract the total sum of two tables
But we have some problem here: you may have null values (because you may not have some of the blood groups present in one of tables) that give the wrong result. you must change the null values to zero with COALESCE() function:
SUM(COALESCE(donates.amount,0) - COALESCE(orders.amount,0))
We must extra check if the result does not equal to null:
COALESCE(SUM(COALESCE(donates.amount,0) - COALESCE(orders.amount,0)),0)
how to make them positive (subtract which one first)
And at last if you want to avoid negative numbers you must use mysqli math functions named ABS() that give you absulute value:
ABS(COALESCE(SUM(COALESCE(donates.amount,0) - COALESCE(orders.amount,0)),0))
so your query will look like this:
$sql = "SELECT donates.blood_group as blood_group,
COALESCE(donates.amount,0) as donates_amount,
COALESCE(orders.amount,0) as orders_amount,
ABS(COALESCE(SUM(COALESCE(donates.amount,0) - COALESCE(orders.amount,0)),0)) as needed_amount
FROM `donates`
LEFT JOIN `orders`
ON donates.blood_group = orders.blood_group
GROUP BY donates.blood_group";
how to show the result even if one blood group is not presented on
the other (full join)
In order to make full join you must use union with the invers form of your query. so that you find other records in orders table and unite the results into one results:
$sql = "SELECT donates.blood_group as blood_group,
COALESCE(donates.amount,0) as donates_amount,
COALESCE(orders.amount,0) as orders_amount,
ABS(COALESCE(SUM(COALESCE(donates.amount,0) - COALESCE(orders.amount,0)),0)) as needed_amount
FROM `donates`
LEFT JOIN `orders`
ON donates.blood_group = orders.blood_group
GROUP BY donates.blood_group
UNION
SELECT orders.blood_group as blood_group,
COALESCE(donates.amount,0) as donates_amount,
COALESCE(orders.amount,0) as orders_amount,
ABS(COALESCE(SUM(COALESCE(orders.amount,0) - COALESCE(donates.amount,0)),0)) as needed_amount
FROM `orders`
LEFT JOIN `donates`
ON orders.blood_group = donates.blood_group
GROUP BY orders.blood_group";

How to separate data extracted from the table in PHP

I extracted data from a database and sorted it based on the id. Now i need to separate out the rows with different ids. The aim is to find out the total price for each id and the latest date.
b_id price date
---- ----------------
1 98.30 2014-05-14
1 65.70 2014-05-07
2 14.40 2014-05-06
2 55.60 2014-05-07
2 38.20 2014-04-06
3 84.40 2014-04-02
3 31.30 2014-04-12
3 74.40 2014-05-06
I tried to separate it using -
while ($row = mysqli_fetch_array($result1)) {
if($row['b_id'] == 1){
}
}
But i cannot hard code it. How can i separate out the rows? Am i doing it wrong?
You can do what you want rigth on your query. It would be like:
select b_id, max(date) as maxdate, sum(price) total
from your table
group by b_id
order by b_id
If you want the total price, your extraction could be
SELECT b_id, SUM( price) AS total_price FROM your_table GROUP BY b_id
while ($row = mysqli_fetch_array($result1)) {
echo "Id : " . $row['b_id'] . " Price : " . $row['total_price'];
}
You should use SQL to achieve your goal. It's usually faster when the database handles simple calculations:
SELECT b_id,
SUM(price) AS 'Price',
MAX(date) AS 'Date'
FROM YourTable
GROUP BY b_id

How to get the next row in sql

I have a table that is something like this
id | names | value
1 Vicky 43
2 Erica 23
3 Rueben 33
4 Bob 54
5 Chris 60
Then I set them in order according to their value. Now the table looks like this.
id | names | value
5 Chris 60
4 Bob 54
1 Vicky 43
3 Rueben 33
2 Erica 23
Now the starting point is id 5 which has a name of Chris and a value of 60. My goal is, to get the next row which has an id of 4 and name of Bob and a value of 54.
You just need to limit the resultset:
SELECT * from table
ORDER BY value DESC
LIMIT 1, 1
Output:
| ID | NAMES | VALUE |
|----|-------|-------|
| 4 | Bob | 54 |
Fiddle here.
The LIMIT basically works this way: the first number sets the starting point (being 0 the minimal value) and the second number the amount of items to fetch (in this case only one).
Edit:
A different way of understanding the question would be: Given a value for a particular field (EG: id field with value of 5)... what would be the previous record? As we have the id 4 in the data we should return that one.
That could be accomplished this way:
SELECT * from t
WHERE id < 5
ORDER BY id DESC
LIMIT 1
Fiddle here.
This way you can traverse the results in both orders (ASC and DESC) and also get both the next or previous (> or <) rows.
If your current ID is for example 4 then
Next:
select * from foo where id = (select min(id) from foo where id > 4)
previous:
select * from foo where id = (select max(id) from foo where id < 4)
sql server:
with temp as
(
SELECT ROW_NUMBER() OVER (ORDER BY value desc) AS ROWID, * FROM table_name
)
SELECT * from temp where ROWID=2
mysql:
SELECT * from table
ORDER BY value DESC
LIMIT 1, 1
I get the feeling that this is a PHP related question?
If that's so, then you can use PHP's mysql or mysqli_fetch functions to get what you want... along with a loop
This is your basic loop-through-a-mysql-query
$sql = mysql_query( "SELECT * from table ORDER BY value DESC" );
while ( $r = mysql_fetch_array( $sql ) ) {
echo $r['value'] . "<br />\n";
}
If you want to have them all at your disposal and be able to call either one of them at will, you will need to store the data in an accessible array, like so
$sql = mysql_query( "SELECT * from table ORDER BY value DESC" );
$theData = array();
while ( $r = mysql_fetch_array( $sql ) ) {
$theData[] = $r['value'];
}
Then, to access the SECOND value, use this
echo $theData[1];

mysql query to count and sum

i have a table where same data is appearing again and again the table structure is like below.id is autoincrement.pm is for userid.it will appear again and again like beliw table.i want to display the output as the extract of entire table in descending order. suppose the table consists of 100 rows and the userid 15 comes 10 times which is highest then it should come at the top then the other id which is coming next like that . i tried but not working here is my code as well
id userid
1 33
2 34
3 37
4 33
5 33
6 37
the output i want is
userid nos
33 3
37 2
34 1
please guide . i tried with this code
$res = sql_query("select count(userid) as total from tableA");
echo'<table>';
while ($row = sql_fetch_array($res)) {
echo ' <tr><td>'.$row['userid'].'</td></tr></table>';
You need to use a GROUP BY statement
SELECT userid, COUNT(userid) AS nos FROM tableA
GROUP BY userid ORDER BY nos DESC;
SELECT userid, COUNT(userid) FROM tableA AS nos GROUP BY userid ORDER BY nos DESC
Then you can access:
$row['userid'] for the user ID
$row['nos'] for the count
Your looping methodology is wrong.
$res = sql_query("select userid, count(userid) as total from tableA group by userid order by total desc");
echo'<table>';
while ($row = sql_fetch_array($res)) {
echo ' <tr><td>'.$row['userid'].'</td><td>'.$row['total'].'</td></tr>';
}
echo '</table>';

Checking users options from default

I have table:
user_id | song_id| points
--------|----------------
2 | 1 | 0
2 | 2 | 1
2 | 3 | 2
2 | 4 | 3
2 | 5 | 4
And I need to check if the user have changed the points value.
Therefore it should be something like:
while ($row = mysql_fetch_array($query)) {
$userID = $row['user_id'];
$songID = $row['song_id'];
$points = $row['points'];
if($songID-$points==1){
echo $userID."<br>";
}
But this will print out every occasion of userID where the song-id - points=1.
I need to print out only these user_id's that have all the values =1 and the username must echo'd only once.
EDIT:
SELECT DISTINCT user_id WHERE (song_id - points) = 1
This is half way there. This echo's user_ids' where the song_id - points = 1, but if the user is reordered (i use jQuery sortable) the list, then there can be some rows that is "song_id - points = 1".
My script must echo only these user_id-s, where users every song_id - points = 1, not only one
SELECT DISTINCT user_id FROM table WHERE (song_id - points) = 1
After edit:
SELECT table.user_id
FROM table
LEFT JOIN (
SELECT user_id, COUNT(*) AS C FROM table) AS T2
ON table.user_id = T2.user_id
WHERE (table.song_id - table.points) = 1
GROUP BY table.user_id
HAVING COUNT(*) = T2.C
You can first filter the users which has modified point values:
SELECT DISTINCT user_id FROM table
WHERE (song_id - points) != 1
Then you can use fetch the users which doesn't fit the above condition:
SELECT DISTINCT user_id FROM table
WHERE user_id NOT IN (
SELECT DISTINCT user_id FROM table
WHERE (song_id - points) != 1
)
According to your last edit this last SQL statement might work.
You can check a working example.
Here is what you're looking for:
select user_id from (
select user_id, if(song_id - points = 1, 0, 1) flag from t
) as S
group by user_id
having sum(flag) = 0
And here is a working example.
In case I didn't understand the requirements this shows all users who don't even have one row in which song_id - points != 1, i.e, all users who have all rows that match song_id - points = 1
Or maybe, if you prefer a different approach that might be more efficient:
select distinct t1.user_id from t t1
where not exists (
select * from t t2
where t2.song_id - t2.points != 1 and t1.user_id = t2.user_id
)
Here is the working example.
Not sure I understand the why of the situation, but a simple control-break structure will achieve the desired result ...
$old_id = '';
$good = false;
while($row = mysql_fetch_array($query)){
//check to see if we have a new user ...
if($row['user_id'] != $old_id){
//check to see if all values were == 1
if($good){
echo $old_id . '<br />';
}
//re-initialize variables
$good = true;
$old_id = $row['user_id'];
}
//if value != 1, we won't print the user ...
if($row['song_id'] - $row['points'] != 1){
$good = false;
}
}
//final end-of-loop condition ...
if($good){
echo $old_id . '<br />';
}
OK, here's a query that's a lot more simple than the join above:
SELECT user_id, sum(song_id) as song_total, sum(points) as point_total, count(*) AS cnt FROM table GROUP BY user_id
If the difference between song_id and points is 1 for every song, then the difference between the totals will equal the number of rows for that user ... so using this query:
while($row = mysql_fetch_array($query)){
if($row['cnt'] == ($row['song_total'] - $row['point_total'])){
echo $row['user_id'] . '<br />';
}
}

Categories