select every other row in MySQL without depending on any ID? - mysql

Considering following table that doesn't have any primary key, can I select every other row?
col1 col2
2 a
1 b
3 c
12 g
first select must find: 2, 3
second select must find: 1, 12
is that possible?

In unique MySQL fashion:
select *
from (
select *
, #rn := #rn + 1 as rn
from Table1
join (select #rn := 0) i
) s
where rn mod 2 = 0 -- Use = 1 for the other set
Example at SQL Fiddle.

Try this. I've adapted it from the answer linked below.
I tested it on SQLFiddle and it appears to work.
http://sqlfiddle.com/#!2/0bccf/28
http://sqlfiddle.com/#!2/0bccf/29
Odd Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 1
Even Rows:
SELECT x.*
FROM (
SELECT #rownum:=#rownum+1 rownum, t.*
FROM (SELECT #rownum:=0) r, table t
) x
WHERE MOD(x.rownum, 2) = 0
Adapted from:
MySQL row number

yes possible using temp variable
Example :
set #a := 0;
select * from car_m_city WHERE mod((#a:=#a+1), 2) = 1
Explanation :
here in sql we declare #a( set #a := 0;) temp variable.(#a:=#a+1) now #a increment by 1.jsut like simple way to check odd or even
mod((#a:=#a+1), 2) = 1 for odd data
mod((#a:=#a+1), 2) = 0 for even data

This works for me.
SET #row_number = 0;
select* from (
SELECT
(#row_number:=#row_number + 1) AS num, col1,col2
FROM
TABLE1
) as t WHERE num%2=0
You can use mod 1 for odd or mod 0 for even rows

This should work for MySQL:
SELECT col1, col2
FROM (
SELECT col1, col2, #rowNumber:=#rowNumber+ 1 rn
FROM YourTable
JOIN (SELECT #rowNumber:= 0) r
) t
WHERE rn % 2 = 1
This uses % which is the MOD operator.
And here is the sample fiddle: http://sqlfiddle.com/#!2/cd31b/2

Related

Mysql query get SUM() specific row?

Is it possible to get specific row in query using like SUM?
Example:
id tickets
1 10 1-10 10=10
2 35 11-45 10+35=45
3 45 46-90 10+35+45=90
4 110 91-200 10+35+45+110=200
Total: 200 tickets(In SUM), I need to get row ID who have ticket with number like 23(Output would be ID: 2, because ID: 2 contains 11-45tickets in SUM)
You can do it by defining a local variable into your select query (in form clause), e.g.:
select id, #total := #total + tickets as seats
from test, (select #total := 0) t
Here is the SQL Fiddle.
You seem to want the row where "23" fits in. I think this does the trick:
select t.*
from (select t.*, (#total := #total + tickets) as running_total
from t cross join
(select #total := 0) params
order by id
) t
where 23 > running_total - tickets and 23 <= running_total;
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(CAST(d.RunningTotal - d.tickets + 1 AS CHAR(10)))
,'-'
,TRIM(CAST(d.RunningTotal AS CHAR(10)))
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
id
,tickets
,#total := #total + tickets as RunningTotal
FROM
test
CROSS JOIN (select #total := 0) var
ORDER BY
id
) d
This is similar to Darshan's answer but there are a few key differences:
You shouldn't use implicit join syntax, explicit join has more functionality in the long run and has been a standard for more than 20 years
ORDER BY will make a huge difference on your running total when calculated with a variable! if you change the order it will calculate differently so you need to consider how you want to do the running total, by date? by id? by??? and make sure you put it in the query.
finally I actually calculated the range as well.
And here is how you can do it without using variables:
SELECT
d.id
,d.tickets
,CONCAT(
TRIM(d.LowRange)
,'-'
,TRIM(
CAST(RunningTotal AS CHAR(10))
)
) as TicketRange
,d.RunningTotal
FROM
(
SELECT
t.id
,t.tickets
,CAST(COALESCE(SUM(t2.tickets),0) + 1 AS CHAR(10)) as LowRange
,t.tickets + COALESCE(SUM(t2.tickets),0) as RunningTotal
FROM
test t
LEFT JOIN test t2
ON t.id > t2. id
GROUP BY
t.id
,t.tickets
) d

MySQL select first row then skip few

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

SELECT Current and Previous row WHERE condition

id value
---------
1 a
2 b
3 c
4 a
5 t
6 y
7 a
I want to select all rows where the value is 'a' and the row before it
id value
---------
1 a
3 c
4 a
6 y
7 a
I looked into
but I want to get all such rows in one query.
Please help me start
Thank you
I think the easiest way might be to use variables:
select t.*
from (select t.*,
(rn := if(value = 'a', 1, #rn + 1) as rn
from table t cross join
(select #rn := 0) params
order by id desc
) t
where rn in (1, 2)
order by id;
An alternative method uses a correlated subquery to get the previous value and then uses this in the where clause:
select t.*
from (select t.*,
(select t2.value
from table t2
where t2.id < t.id
order by t2.id desc
limit 1
) as prev_value
from table t
) t
where value = 'a' or prev_value = 'a';
With an index on id, this might even be faster than the method using variables.

Select a row along with its next and previous rows

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)

How to select certain numbers of groups in MySQL?

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;