MySQL query to select both greater than and less than value [duplicate] - php

This question already has an answer here:
How to find the previous and next record using a single query in MySQL?
(1 answer)
Closed 8 years ago.
mytable
id name
------- --------
1 James
2 John
3 Edward
4 Bill
above is my table, I'm trying to build a query which can select both the greater than and less than value. For example $current_id = 3, so what I need to select is 2 and 4 from the table with a single query. I can obtain the one(less than or greater than) value but not sure how to combine the query to obtain both.
Query
SELECT mytable.id FROM mytable WHERE id > $current_id;

(SELECT id
FROM mytable
WHERE id > $current_id
ORDER BY id ASC
LIMIT 1)
UNION
(SELECT id
FROM mytable
WHERE id < $current_id
ORDER BY id DESC
LIMIT 1)

SELECT mytable.id FROM mytable
WHERE id = $current_id +1
OR id=$current_id -1;
Here we are using OR gate that will check both conditions and it will run both conditions, if both are passing then it will show the result of both conditions or if any one conditions is passing then it will show the result only of that condition that is passing.

Related

SQL multi order

Assume this array is my db table.
array('1','1','1','2','2','2','3','3','3','4','4','4','4','5','5','5','5');
in that table i have status from 1 to 5. but i want get data first with status = 2,sec 5 ... ,1,3,4.
is it possible ? if not how can i do it with php.
You may order using FIELD:
SELECT *
FROM yourTable
ORDER BY FIELD(status,2,5,1,3,4);
Demo
If you get the array from a table then you could use a CASE WHEN in the ORDER BY of your query
For example:
select num
from YourTable
order by (case when num = 2 then 1 when num = 5 then 2 else num+2 end);

How to use the result of a select as offset in an SQL query

I was trying to create a single SQL query to return what I need, instead of creating 2 querys, but I need to use the result of one of the querys as the offset of the other one.
My table has user answers with scores, each user may have multiple answers in that table. And I want to calculate the middle point of the table of ordered scores.
Example:
User answers:
User 1 - 5 points
User 1 - 15 points
User 2 - 8 points
User 3 - 12 points
Ranking Table:
User 1 - 20 points
User 3 - 12 points < Middle point
User 2 - 8 points
Solution:
The first query calculates the middle point:
SELECT CEILING(count(Distinct(id_user)) / 2) as position
FROM us_user_response
where id_round=1
Query result:
position : 2
This second query creates the ordered ranking table:
SELECT sum(points) as score
FROM us_user_response
where id_round=1
GROUP BY id_user
Order by score DESC
Now I want to create one big query that returns the score of the middle user, I just need to use the first query result as offset of the second query:
SELECT sum(points) as score
FROM us_user_response
where id_round=1
GROUP BY id_user
Order by score DESC LIMIT 1
OFFSET (SELECT CEILING(count(Distinct(id_user)) / 2) as position
FROM us_user_response where id_round=1)
Of course, this doesn't work, is there any way to use a result as offset?
EDIT:
The queries work nice! My question is if there is any way to use the result of a query as the offset of another. So I could accomplish this in one single query.
Try something like this:
SET #line_id = 0;
SET #line_offset = (
SELECT CEILING(count(Distinct(id_user)) / 2) as position
FROM us_user_response
WHERE id_round = 1
);
SELECT sum(points) as score,
IF((#line_id := #line_id + 1) = #line_offset, 1, 0) AS useit
FROM us_user_response
WHERE id_round = 1
GROUP BY id_user
HAVING useit = 1
ORDER BY score;

mysql - get explicit value and random values in one query [duplicate]

This question already has an answer here:
Mysql Select some random rows and plus one specific row
(1 answer)
Closed 9 years ago.
Is it possible to get a specific value (like ID = 5) and in addition to that, two or three other random values from the same table?
Here's my query:
SELECT name, solution, MAX( solution )
FROM tracks
WHERE id !=5
GROUP BY name
ORDER BY RAND( )
LIMIT 0 , 30
What I want to do:
I have a quiz where I need to get three answers from the database. In my first query I'm getting the actual answer and in the second (the query above) I get the other two answer that are NOT the actual answer (ID != ).
The problem is, in my table, 4 values are the same, they have the same name, so if my acutal answer is ID = 5, there is the possibility that the query above will select the ID with 9 (it's the same name as ID = 5).
How can I avoid that?
Thank you!
Perhaps you could add a subquery to your where clause to lookup all solutions that are not the id and do not have the same solution name:
SELECT name, solution, MAX( solution )
FROM tracks
WHERE id !=5
--check that the id is not in the subquery and the name doesnt match:
AND id not in (select id from tracks t where id!=5 and t.name <> name)
GROUP BY name
ORDER BY RAND( )
LIMIT 0 , 30
Random results are random. If you want to ensure that you don't get results with the same name as the answer, you have to filter by name.
SELECT name, solution, MAX(solution)
FROM tracks
WHERE id != 5 AND name != (SELECT name FROM tracks WHERE id = 5)
GROUP BY name
ORDER BY RAND()
LIMIT 0 , 30
Yes, it's possible. Use UNION for that. (sqlfiddle here)
SELECT * FROM ( (
SELECT id, name, max(solution) as solution
FROM tracks
WHERE id = 5
GROUP BY name
LIMIT 0, 1
)
UNION (
SELECT id, name, solution
FROM tracks
WHERE id != 5
GROUP BY name
)) tmp ORDER BY RAND() LIMIT 0, 3

Ordering the SQL query in a particular order

Say i have a table Guest and it has column g_id : values 1 to 10.
Now i want the query to return me the g_id's neither in ascending order nor in descending..
but i want the 4th then 3rd and then 5th entry, in this particular order.
Also i want just the 4th 3rd and 5th entry.
say my entries have an id and a name . ;i.e. my table Guest has these two tables.
Now my table is as following.
1 A
2 B
3 C
4 D
5 E
6 F
7 G
8 H
9 I
10 J
Now i want just the entry with 4th 3rd and 5th g_id, and in this particular order.
How do i write the SQL query?
Thanks.
Select * from Guest ___________???
Kindly fill in the gaps.
You can use a CASE statement in your ORDER BY to use a fake column to sort on and a WHERE IN clause to only return the values you need.
SELECT *
FROM Guest
WHERE g_id IN (3, 4, 5)
ORDER BY
CASE WHEN g_id = 4 THEN 1
WHEN g_id = 3 THEN 2
WHEN g_id = 5 THEN 3
END
What is the order that deteremines whether something is 4th, 3rd or 5th? Without an ORDER BY clause, the data is returned in an indeterminate order by SQL. You cannot rely on the order that rows are entered or stored in the database table itself.
You can hard-code what you are asking like this:
select *
from Guest
order by case
when g_id = 4 then 1
when g_id = 3 then 2
when g_id = 5 then 3
else 4
end
One solution is the case statement:
select g_id from (
select g_id, case g_id
when 4 then 1
when 3 then 2
when 5 then 3
else 0
end virtcol
where virtcol != 0
order by virtcol
);
I'm not sure how set your ordering will be, but you can order by specifics:
ORDER BY
g_id = 4 DESC,
g_id = 3 DESC,
g_id = 5 DESC
You may be better off selecting the entries as they are and doing something like this in your php code:
$order = array('4 ', '3 ', '5 ');
$data = array();
while ($row = $result->fetch()) {
$data["$row->g_id "] = $row;
}
$data = array_merge(array_flip($order), $data);
I think that the answer mostly depends on the DBMS you are working on.
In Oracle the query below, even though inefficient, should work
select * from
(select * , rownum as order from guest order by id asc ) b
where b.order = 4
UNION
select * from
(select * , rownum as order from guest order by id asc ) b
where b.order = 3
UNION
select * from
(select * , rownum as order from guest order by id asc ) b
where b.order = 5
Not sure if something of more efficient is possible with a simple query,
i would use the monster above only and only if the table you are querying is very small.
You also have another option if the table is big and you have to extract only the first rows. In the case you described, I would retrieve the first 5 rows and then programmatically I would extract the rows in position 4,3,5.
you can extract the first 5 rows with this query in oracle
select * from guest order by id asc where rownum < 6
This query will get you the 3rd, 5th, and 4th items (limit 2, 1 means "retrieve starting with 3rd item, with total number retrieved = 1 records)
(select g_id from Guest limit 2,1)
UNION (select g_id from Guest limit 4,1
UNION (select g_id from Guest limit 3,1)

Select adjacent records in Mysql

Assuming this table is ordered by date
id | date | customer
3 | 2009-10-01| Frank
1 | 2010-10-11| Bob
4 | 2010-11-01| Mitchel
2 | 2010-11-02| Jim
I would like to make a query so that knowing ID = 4 the resulting rows are
$row[0]['id'] == 1 //previous
$row[1]['id'] == 4 //most recent/current
$row[2]['id'] == 2 //next
A mysql only solution would be best, but if there is an elegant php solution that would be cool as well.
As the table IS sorted by date column, you can run following queries to get it:
For previous row:
select * from tablename where `date` < (select `date` from tablename where id=4) order by `date` desc limit 1
For current row:
select * from tablename where id=4
For next row:
select * from tablename where `date` > (select `date` from tablename where id=4) order by `date` asc limit 1
Output: These three queries return the result (one by one) as following:
id date customer
1 2010-10-11 Bob
4 2010-11-01 Mitchel
2 2010-11-02 Jim
Since you are ordering by date, but basing the row you want the adjacent rows on id, your going to have to do 2 queries. The first to determine the date for the ID you have selected, the second to get the adjacent rows.
Step 1 - Get the date
Select date
FROM yourtable
WHERE id = 4
Step 2 - Get all the rows
SELECT *
FROM yourtable
WHERE date IN ( (select MAX( date ) from yourtable where date < $datefromquery1)
, $datefromquery1
, (select MIN( date ) from yourtable where date > $datefromquery1)
)
The LIMIT function can take two arguments, an offset and a number of rows to return. In your case, you want the offset to be (the number of rows with dates before the desired row) - 1, or in this case 2 - 1 = 1, and the number of rows to be three. So the SQL you want is
SELECT * FROM customers ORDER BY date ASC LIMIT 1,3;
and the number "1" will be the result of the query
SELECT COUNT(*)-1 FROM customers WHERE date > "2010-11-01";
I don't believe MySQL will let you use a subselect or function value as the argument of LIMIT, so you'll have to store that using PHP and construct the next query that way.

Categories