PHP/SQL : If statement within the query? - php

Hi I am trying to create something but I can't have my total number being a negative. So basically I got values that are negative that can be multiplied into a somewhat complex mathematics equation.
So essentially... user inputs a data from -1 to 1. (-1, 0, 1)
And it get's multiplied into my formula. So my SQL query looks like this... (this part works!)
SELECT *, a, b, c AS TOTALNUMBER FROM MATH
ORDER BY TOTALNUMBER DESC
However, I need the total number to always be positive. So I have been trying for the past few hours to figure this out. I am sort of new to php/sql.
I am trying to include something like...
if (TOTALNUMBER < 0 ) {
TOTALNUMBER * -1.0
}
However I have no idea where to include this in the query or how to write it properly.
To clarify and update what I am looking for...
User can input -1,0,1
Data for A, B, C is for example. 10, 15, 20
User inputs: 1, -1, 0
A total = 10
B total = -15
C total = 0
Total ABC = -5
However, I need total to be 5 instead of -5 without changing any A, B, C values.

use like this
SELECT *, a, b, ABS(c) AS TOTALNUMBER FROM MATH
ORDER BY TOTALNUMBER DESC

IF(expr1,expr2,expr3)
If expr1 is TRUE (expr1 <> 0 and expr1 <> NULL) then IF() returns expr2; otherwise it returns expr3. IF() returns a numeric or string value, depending on the context in which it is used.
SELECT a, b, c, If (c <0 , c * -1, c) AS TOTALNUMBER FROM MATH
ORDER BY TOTALNUMBER DESC;
If you want the sum of all the fields to be your total number, assuming you have an id field:
SELECT a,b,c,ABS((sum(a)+(b)+(c))) AS TOTALNUMBER FROM MATH
group by mathid ORDER BY TOTALNUMBER DESC;
Here is an example:
mysql> select * from math;
+--------+----------+
| idmath | mathcol1 |
+--------+----------+
| 1 | 1 |
| 2 | 3 |
| 3 | -1 |
| 4 | -3 |
+--------+----------+
4 rows in set (0.00 sec)
mysql> SELECT idmath, If (mathcol1 <0 , mathcol1 * -1, mathcol1) AS TOTALNUMBER
FROM MATH ORDER BY TOTALNUMBER DESC;
+--------+-------------+
| idmath | TOTALNUMBER |
+--------+-------------+
| 2 | 3 |
| 4 | 3 |
| 1 | 1 |
| 3 | 1 |
+--------+-------------+
4 rows in set (0.00 sec)
mysql> SELECT idmath, mathcol1, If (mathcol1 <0 , mathcol1 * -1, mathcol1) AS TO
TALNUMBER FROM MATH ORDER BY TOTALNUMBER DESC;
+--------+----------+-------------+
| idmath | mathcol1 | TOTALNUMBER |
+--------+----------+-------------+
| 2 | 3 | 3 |
| 4 | -3 | 3 |
| 1 | 1 | 1 |
| 3 | -1 | 1 |
+--------+----------+-------------+
4 rows in set (0.00 sec)
mysql> SELECT mathcol1,mathcol2,mathcol3, (sum(ABS(mathcol1))+(mathcol2)+(mathco
l3)) AS TOTALNUMBER FROM MATH group by idmath ORDER BY TOTALNUMBER DESC;
+----------+----------+----------+-------------+
| mathcol1 | mathcol2 | mathcol3 | TOTALNUMBER |
+----------+----------+----------+-------------+
| 3 | 2 | 3 | 8 |
| -3 | 2 | 3 | 8 |
| -1 | 2 | 3 | 6 |
| 1 | 2 | 3 | 6 |
+----------+----------+----------+-------------+
4 rows in set (0.00 sec)
You can read more here at dev.mysql.

Related

Get neighboring rows (2 above and 2 below) of a certain row in PHP while loop

I have a table like so (after doing a query on it to order it by score):
+---+-------+------+
|id | level |score |
+---+-------+------+
| 4 | 1 | 30 |
| 3 | 1 | 35 |
| 1 | 1 | 40 |
| 5 | 1 | 45 |
| 7 | 1 | 50 |
| 8 | 1 | 55 |
+---+-------+------+
I will output that to php in a while loop. So each row in the while loop will be the same as in the table above.
Essentially what I want to do is show 5 of these rows in a table (in html), with a certain row (e.g. where id=5) in the middle and have the two rows above and below it (in the correct order). This will be like a score board but only showing the user's score with the two above and two below.
E.g. say the user is id=5, I want to show
+---+-------+------+
|id | level |score |
+---+-------+------+
| 3 | 1 | 35 |
| 1 | 1 | 40 |
| 5 | 1 | 45 |
| 7 | 1 | 50 |
| 8 | 1 | 55 |
I am wondering does anyone know a way of doing this in php?
Basically
//select query output is in while loop
//get a certain row of the loop
//get the two rows above it and two rows below it
One method uses a lot of variables:
select t.*
from (select t.*,
lag(id, 1) over (order by score) as prev_id,
lag(id, 2) over (order by score) as prev_id2,
lead(id, 1) over (order by score) as next_id,
lead(id, 2) over (order by score) as next_id2
from t
) t
where 5 in (prev_id, prev_id2, next_id, next_id2, id)
order by score;
An alternative method is something like this:
(select t.*
from t
where t.score <= (select t2.score from t t2 where t2.id = 5)
order by score desc
limit 3
) union all
(select t.*
from t
where t.score > (select t2.score from t t2 where t2.id = 5)
order by score
limit 2
)
order by score;
This exactly syntax may not work in all databases, but the idea can easily be translated in whatever dialect of SQL. This also assumes that the scores are unique.

mysql - Max occurences of a given value in a table

I have a table like this
+-------+-------+-------+-------+
| id | cid | grade |g_point|
+-------+-------+-------+-------+
| 1 | 10 | A+ | 1 |
| 2 | 10 | A+ | 1 |
| 3 | 10 | B | 3 |
| 4 | 11 | A | 2 |
| 5 | 11 | A+ | 1 |
| 6 | 12 | B | 3 |
the column g_point is the values associated to each grade. forexample A+ grade considers highest so I assign the value of A+ is one(highest starts from 1 to 10) and so on. These g_point values are constant. Now what I want to do is I want to show the maximum grade against each course and also if somehow there are only two entries of different grades I want to compare it with the g_point and choose whose value is lower because lower integer value means higher grade. the result should be like this and also sorted from top grade to lower.
+-------+-------+
| cid | grade |
+-------+-------+
| 10 | A+ |
| 11 | A+ |
| 12 | B |
I have tried this query
SELECT coursecodeID AS cid, (SELECT grade
FROM feedback
WHERE coursecodeID = cid
GROUP BY grade
ORDER BY COUNT(*) DESC LIMIT 0,1) AS g
FROM feedback
GROUP BY coursecodeID
but in this query I don't know how can I compare it with g_point value and also the courses is not showing in order(from highest grade to lowest).
NOTE: I want to choose the grade having the maximum number of occurrences per course id. For example here in this table course id 10 has 2 A+ grade so we'll consider A+ and if clash happens like one is A+ and the other is B+, then we'll have to compare it with the g_point
This works, but needs the 'g_point' to alse be returned.
SELECT cid,grade,MIN(g_point)
FROM grades
GROUP BY cid
This is more reliable, as it generates the Grade in the sub-query, and then appends it to the main table.
SELECT cid, (
SELECT grade
FROM grades g2
WHERE g2.cid = g1.cid
ORDER BY g_point
LIMIT 1
) AS grade
FROM grades g1
GROUP BY cid
You can use the following query:
SELECT DISTINCT m1.cid, m1.grade
FROM mytable AS m1
INNER JOIN (
SELECT cid, MIN(g_point) AS maxGrade
FROM mytable
GROUP BY cid ) m2
ON m1.cid = m2.cid AND m1.g_point = m2.maxGrade
The derived table contains the minimum g_point per cid. If you join it back to the original table, then you can get the maximum grade per cid.
Demo here
EDIT:
You can alternatively use a correlated sub-query:
SELECT cid, (SELECT grade
FROM mytable AS m2
WHERE m2.cid = m1.cid
ORDER BY g_point LIMIT 1) AS maxGrade
FROM mytable AS m1
GROUP BY cid
Demo here
EDIT2:
It looks like you want to get the grade having the maximum number of occurrences per cid. In case there are more than one grades sharing this maximum number, then fetch the grade with the lowest g_point.
You can do it using variables:
SELECT cid, grade
FROM (
SELECT cid, grade,
#row_number := IF (#cid <> cid,
IF (#cid := cid, 1, 1),
IF (#cid := cid, #row_number+1, #row_number+1)) AS rn
FROM (
SELECT cid, grade,
COUNT(*) AS cnt,
(SELECT g_point
FROM mytable AS m2
WHERE m1.grade = m2.grade
LIMIT 1) AS g_point
FROM mytable AS m1
GROUP BY cid, grade
) t
CROSS JOIN (SELECT #row_number:=-1, #cid:=-1) AS vars
ORDER BY cid, cnt DESC, g_point
) s
WHERE rn = 1
Demo here
Something to think about...
SELECT * FROM ints;
+---+
| i |
+---+
| 0 |
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
+---+
SELECT i
, CONCAT(CHAR((i/2)+64),IF(MOD(i,2)=1,'+',''))n
FROM ints
WHERE i > 0;
+---+------+
| i | n |
+---+------+
| 1 | A+ |
| 2 | A |
| 3 | B+ |
| 4 | B |
| 5 | C+ |
| 6 | C |
| 7 | D+ |
| 8 | D |
| 9 | E+ |
+---+------+

Count data in same sentence

I have table :
==========================================================
|id | before | after | freq | id_sentence | document_id |
==========================================================
| 1 | a | b | 1 | 0 | 1 |
| 2 | c | d | 1 | 1 | 1 |
| 3 | e | f | 1 | 1 | 1 |
| 4 | g | h | 2 | 0 | 2 |
==========================================================
I want to get the number of data depend on the id_sentence and freq so the result must be 1 2 1
here's the code :
$query = mysql_query("SELECT freq FROM tb where document_id='$doc_id' ");
while ($row = mysql_fetch_array($query)) {
$stem_freq = $row['freq'];
$total = $total+$stem_freq;
but the result is still wrong. please, help me.. thank you :)
If I understand your question, you are trying the calculate the sum of freq for each distinct id_sentence for a particular document_id.
Try the following SQL:
SELECT id_sentence, SUM(freq) as freq FROM tb WHERE document_id = 1 GROUP BY(id_sentence)
The result will be rows of data with the id_sentence and corresponding total freq. No need to manually sum things up afterwards.
See this SQL Fiddle: http://sqlfiddle.com/#!2/691ed/8
I think you could do something like
SELECT count(*) AS count FROM tb GROUP BY(id_sentence,freq)
to do the counting you want. You could even do something like
SELECT count(*) AS count, id_sentence, freq FROM tb GROUP BY(id_sentence,freq)
to know which id_sentence,freq combination the count is for.

insert incremental values in an insert ... select statement mysql

I am trying to select a number of rows in a table, reverse the values in one column and reinsert them into the table. Here is an example of what I am doing, say I have the following data:
+-------+--------+-------+
| ORDER | X | Y |
+-------+--------+-------+
| 0 | 12 | 5 |
| 1 | 16 | 3 |
| 2 | 19 | 2 |
+-------+--------+-------+
I want to select it and reinsert it into the same table with the ORDER reversed as so:
+--------+--------+-------+
| PORDER | X | Y |
+--------+--------+-------+
| 2 | 12 | 5 |
| 1 | 16 | 3 |
| 0 | 19 | 2 |
+--------+--------+-------+
I am able to duplicate the rows and reinsert them, no problem using an insert ... select like this:
INSERT INTO myTable (porder, x, y) SELECT porder, x, y FROM myTable
but I have had no success reversing the order. I have tried
INSERT INTO myTable (porder, x, y) SELECT (SELECT porder FROM myTable ORDER BY porder DESC), x, y FROM myTable but that throws an error
It would be fine to simply ignore the porder column and insert new values from 0 to the highest number in the sequence (2 in my above example) but I don't know how to add sequential numbers in a multiple-row insert statement in mysql.
I know how to do this with php but I was thinking there must be a more elegant solution in just SQL
If you know the max-value of order, you can simply do (assuming max(order) = 2)
UPDATE `myTable` SET `PORDER` = 2 - `PORDER`
Example:
+--------+------------+
| PORDER | 2 - PORDER |
+--------+------------+
| 0 | 2-0 = 2 |
| 1 | 2-1 = 1 |
| 2 | 2-2 = 0 |
+--------+------------+
try this
INSERT INTO myTable(`porder`, x, y) SELECT (SELECT MAX(`porder`) FROM myTable) - `porder`, x, y FROM myTable

MySQL query question

I have a simple question regrading MySQL. Is it possible to return the rows between row 'x' and row 'y'? It's sort of hard to explain - for the sake of an example: Return rows 6 through 10, excluding rows 1-5 and rows 11+. Thanks! ;D
Use LIMIT. Remember to combine it with ORDER BY for the results to make any sense.
SELECT fields, ...
FROM table
ORDER BY something_sensible
LIMIT 5, 5
(Start from row 6, take 5 rows)
SELECT * FROM table LIMIT 5, 5
http://dev.mysql.com/doc/refman/5.5/en/select.html and look at LIMIT section
Yes, here's an example:
SELECT * FROM myTable LIMIT 5, 5
From the manual (http://dev.mysql.com/doc/refman/5.0/en/select.html):
The LIMIT clause can be used to constrain the number of rows returned by the SELECT statement. LIMIT takes one or two numeric arguments, which must both be nonnegative integer constants (except when using prepared statements).
With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. The offset of the initial row is 0 (not 1):
SELECT * FROM tbl LIMIT 5,10; # Retrieve rows 6-15
mysql> select * from employees order by emp_id;
+--------+-----------------+---------+
| emp_id | name | boss_id |
+--------+-----------------+---------+
| 1 | f00 | NULL |
| 2 | ali later | 1 |
| 3 | megan fox | 1 |
| 4 | jessica alba | 3 |
| 5 | eva longoria | 3 |
| 6 | keira knightley | 5 |
| 7 | liv tyler | 6 |
| 8 | sophie marceau | 6 |
+--------+-----------------+---------+
8 rows in set (0.00 sec)
mysql> select * from employees order by emp_id limit 2,4;
+--------+-----------------+---------+
| emp_id | name | boss_id |
+--------+-----------------+---------+
| 3 | megan fox | 1 |
| 4 | jessica alba | 3 |
| 5 | eva longoria | 3 |
| 6 | keira knightley | 5 |
+--------+-----------------+---------+
4 rows in set (0.00 sec)
Why don't you use an Auto Increment field? Or you can use LIMIT keyword like:
SELECT * FROM tablename WHERE LIMIT 0, 5
This will show records 1,2,3,4,5

Categories