Situation:
At the moment I have 3 queries:
First - Gets data by id which has ordering position;
Second - Gets data by position-1;
Third - Gets data by position+1.
I want to have only 1 Query which could take "needed one" by id + previous and next ones if they exists.
Queries:
First
set #position = 0;
SELECT
`position` FROM
(
SELECT `id`, #position:=#position+1 as `position` FROM {#table}
"other_part_of_query"
ORDER BY `modified_time` DESC
) t
WHERE
t.id = '".id."'
LIMIT 1
Second and third
set #position = 0;
SELECT
`id` FROM
(
SELECT `id`, #position:=#position+1 as `position` FROM {#table}
"other_part_of_query"
ORDER BY `modified_time` DESC
) t
WHERE
t.`position` = '".position."'
LIMIT 1
This is complicated, because you are selecting a row by id, but choosing the adjacent ones by another field, modified_time.
The idea is to use variables to enumerate the rows. And, use another row to calculate the value for the id that you care about. Do this in a subquery, and then select the rows that you want:
SELECT t.*
FROM (SELECT `id`,
#rn := if(#rnid := if(t.id = '".id."', #rn + 1, #rnid),
#rn + 1, #rn + 1
) as rn
FROM {#table} t
"other_part_of_query" cross join
(select #rn := 0, #rnid := 0) vars
ORDER BY `modified_time` DESC
) t
WHERE rn in (#rnid - 1, #rnid, #rn)
You can use extra conditions in your where clause to solve this. Consider the following three conditions:
One row must have the modified_time you want.
One row must have the maximum modified_time that is still less than the one you want. (The previous position)
One row must have the minimum modified_time that is still greater than the one you want. (The next position)
Try this:
SELECT *
FROM myTable
WHERE modified_time = #myParam
OR modified_time = (SELECT MAX(modified_time ) FROM myTable WHERE modified_time < #myParam)
OR modified_time = (SELECT MIN(modified_time ) FROM myTable WHERE modified_time > #myParam);
Selecting next and previous rows of a specific row
SET #j = 0;
SET #i = 0;
SELECT *
FROM (
SELECT id, col1, col2, ..., #j:=#j+1 AS pos
FROM `table`
WHERE col1=... ORDER BY col1 DESC, col2 ASC
) AS zz
WHERE (
SELECT position
FROM (
SELECT id AS id2, #i:=#i+1 AS position
FROM `table`
WHERE col1=... ORDER BY col1 DESC, col2 ASC
) AS zz
WHERE id2=$currId
)
IN (pos-1, pos, pos+1)
Related
Let's say there are millions of records in my_table.
Here is my query to extract rows with a specific name from list:
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4')
How do I limit the returned result per name1, name2, etc?
The following query would limit the whole result (to 100).
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4') LIMIT 100
I need to limit to 100 for each name.
This is a bit of a pain in MySQL, but the best method is probably variables:
select t.*
from (select t.*,
(#rn := if(#n = name, #rn + 1,
if(#n := name, 1, 1)
)
) as rn
from my_table t cross join
(select #n := '', #rn := 0) params
order by name
) t
where rn <= 100;
If you want to limit this to a subset of the names, then add the where clause to the subquery.
Note: If you want to pick certain rows -- such as the oldest or newest or biggest or tallest -- just add a second key to the order by in the subquery.
Try
SELECT * FROM my_table WHERE Name IN ('name1','name2','name3','name4') FETCH FIRST 100 ROWS ONLY
I have a table that looks like this:
I want to get for EACH id the row that has the biggest value in feedbacks. So my expected results should look like this:
I've tried to do this:
SELECT id, course_number, rate_average, max(feedbacks)
FROM [Table]
GROUP BY id;
And I'm getting one row per ID but the row doesn't contain the data of the right row in the original table.
Oh and I'm using mysql.
Try this:
select t.*
from your_table t
inner join (
select
id, max(feedbacks) feedbacks
from your_table
group by id
) t2 on t.id = t2.id and t.feedbacks = t2.feedbacks;
It finds id and maximum feedback and join it with the original table to get the relevant rows.
Please note if there are multiple rows with same id and feedbacks, all those rows will be returned.
If you want one row per id, then think "filter", not "aggregate". One approach is a correlated subquery:
select t.*
from t
where t.feedbacks = (select max(t2.feedbacks)
from t t2
where t2.id = t.id
);
Note: If multiple rows have the same maximum, then this will return all the rows for the id. If this is an issue, you should probably ask another question and specify what you want to return in this case.
You can also achieve this by adding a row number group by id column order by descending order of feedbacks column.
Query
select t1.``id`, t1.`course_number`, t1.`rate_average`, t1.`feedbacks` from
(
select `id`, `course_number`, `rate_average`, `feedbacks`,
(
case `id` when #curA
then #curRow := #curRow + 1
else #curRow := 1 and #curA := `id` end
) as `rn`
from `your_table_name` t,
(select #curRow := 0, #curA := '') r
order by `id`, `feedbacks` desc
)t1
where t1.`rn` = 1;
I'm trying to select first row then skip X next rows then select rest in one query. For example if I have (a,b,c,d,e) in table I need to select "a" (first row) then skip X=2 rows ("b", "c") and then select rest which is "d" and "e", all in one query. So the result would be a,d,e
Try
select *
from
(
select *, #rank := #rank + 1 as rank
from your_table
cross join (select #rank := 0) r
order by colA
) tmp
where rank = 1
or rank > 3
or
select * from your_table
order by colA
limit 1
union all
select * from your_table
order by colA
limit 4, 9999999
You can use a variable to generate a row number:
select
YourField,
YourOtherField
from
(
select id,
YourField,
YourOtherField,
#row := #row + 1 as rownum
from YourTable
cross join (select #row:=0) c
order by YourField -- The field you want to sort by when you say 'first' and 'fourth'
) d
where
rownum = 1 or rownum >= 4
I have the table with data:
And for this table I need to create pegination by productId column. I know about LIMIT N,M, but it works with rows and not with groups. For examle for my table with pegination = 2 I expect to retrieve all 9 records with productId = 1 and 2 (the number of groups is 2).
So how to create pegination by numbers of groups ?
I will be very thankfull for answers with example.
One way to do pagination by groups is to assign a product sequence to the query. Using variables, this requires a subquery:
select t.*
from (select t.*,
(#rn := if(#p = productid, #rn + 1,
if(#rn := productid, 1, 1)
)
) as rn
from table t cross join
(select #rn := 0, #p := -1) vars
order by t.productid
) t
where rn between X and Y;
With an index on t(productid), you can also do this with a subquery. The condition can then go in a having clause:
select t.*,
(select count(distinct productid)
from t t2
where t2.productid <= t.productid)
) as pno
from t
having pno between X and Y;
Try this:
select * from
(select * from <your table> where <your condition> group by <with your group>)
LIMIT number;
First I want to make clear this is not a simple LIMIT x,y question. I want to know if it is possible to do a query like the following peuso query.
SELECT *, OFFSET_OF_ROW()
FROM `table`
WHERE `some_column` = someValue
ORDER BY `some_other_column`;
the pseudo function OFFSET_OF_ROW() should give the number of rows which would come before the selected row (+1) if there was no condition `some_column = someValue`
This isn't particularly efficient, but it will do what you want:
select #rownum := 0;
select * from (
select #rownum := #rownum + 1, id, some_column, sortcol
from `table`
order by `sortcol`
) all_rows
where `some_column` = someValue;