I have a Mysql Database like below:
id , name , col1
and i want to find all rows that: value of col1 of the row is greater than avrage of maximom 5 rows past
for example if I have 50 rows , and if the row #20 has gotten , the avrage of value of col1 of rows #20,#19,#18,#17,#16 should be less than the value of col1 of row #20 , and so on...
Thank you in advance.
What you seem to want here is running average of past M records starting from current record and we need to select the current record if current record's column value is greater than the running average.
Here is my attempt to it:
SET #M := 2;
SELECT * FROM
(
SELECT (#rownumber:= #rownumber + 1) AS rn, yt.*
FROM your_table yt,(SELECT #rownumber:= 0) nums
ORDER BY name, id
) a
WHERE a.var1 >
(
SELECT avg(b.var1)
FROM
(
SELECT (#rownumber:= #rownumber + 1) AS rn, yt.*
FROM your_table yt,(SELECT #rownumber:= 0) nums
ORDER BY name, id
) b
WHERE b.rn > a.rn - #M AND b.rn <= a.rn
)
#M is count of past records to be considered for finding running average.
Here is the code at SQL Fiddle
[EDIT]:
Here is another solution which according to me should be more efficient than correlated query.
SET #M := 2;
SELECT a.* FROM
(
SELECT (#rownumber:= #rownumber + 1) AS rn, yt.*
FROM your_table yt,(SELECT #rownumber:= 0) nums
ORDER BY name, id
) a
JOIN
(
SELECT b.name, b.rn, AVG(c.var1) AS av
FROM
(
SELECT (#rownumber1:= #rownumber1 + 1) AS rn, yt.*
FROM your_table yt,(SELECT #rownumber1:= 0) nums
ORDER BY name, id
) b
JOIN
(
SELECT (#rownumber2:= #rownumber2 + 1) AS rn, yt.*
FROM your_table yt,(SELECT #rownumber2:= 0) nums
ORDER BY name, id
) c
ON b.name = c.name
AND c.rn > (b.rn - #M) AND c.rn <= b.rn
GROUP BY b.name,b.rn
) runningavg
ON a.name = runningavg.name
AND a.rn = runningavg.rn
AND a.var1 > runningavg.av
Here I have used simple inner join to calculate running average and again with inner join have selected rows which have column value greater than average.
Here is the code at SQL Fiddle
Let me know did it prove to be efficient.
Related
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
there is a table having two columns say id and name , i want both columns to be sorted.
table :
id name
3 y
2 z
1 x
output should be
id name
1 x
2 y
3 z
can anybody do it in single sql query ???
You need need to do weird stuff. because what you want to do is weird.
select b1.id, b2.name from
(
select #row := #row +1 as row, id
from broken, (select #row := 0) rr
order by id asc
) b1
inner join
(
select #row2 := #row2 + 1 as row, name
from broken, (select #row2 := 0) rr
order by name asc
) b2
on b1.row = b2.row
demo fiddle: http://sqlfiddle.com/#!9/4d47c/7
Select *
, row_number() over (order by ID) as IDRow
, row_number() over (order by name) as NameRow
into #temp
from table
select a.ID, b.Name from #temp a
full outer join #temp b
on a.IDRow = b.NameRow
order by IDRow, NameRow
If you wanted, you could do this with subqueries instead of the temp table, but it'll probably be faster this way.
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;
I have two tables:
exam_outline_items:
jml_quiz_pool:
Of all the things I've tried, this got me the closest:
select t1.sequence, t1.title, t2.q_cat, t2.q_count
from student_pl.exam_outline_items t1
cross join pe_joomla.jml_quiz_pool t2
where t1.exam_outline_id = 5 and t1.chapter_num > 0
and t2.q_id = 1109 and t2.q_count > 0
group by title
Which produces this result:
I just need those q_cat values to be different, like they are in the 2nd query.
Thanks in advance for your help.
You have to have something to connect them with. If you don't have such a column, you can simulate one by creating a rownumber with variables.
select sequence, title, q_cat, q_count from (
select t1.sequence, t1.title, #r1 := #r1 + 1 as rownumber
from student_pl.exam_outline_items t1
, (select #r1 := 0) var_init
where t1.exam_outline_id = 5 and t1.chapter_num > 0
order by t1.sequence
) a
inner join
(
select t2.q_cat, t2.q_count, #r2 := #r2 + 1 as rownumber
from pe_joomla.jml_quiz_pool t2
, (select #r2 := 0) var_init
where t2.q_id = 1109 and t2.q_count > 0
order by t2.q_cat
) b on a.rownumber = b.rownumber;
Also note, that I used order by in those queries. In a database you have no sort order unless you explicitly set it with order by.
I'm trying to produce an incremental counter (column 'rownum' in the query below) in an SQL select clause. the counter should start over each time a new user switches.
SELECT * FROM (
SELECT CONCAT(' ',g.node1,' ',g.node2),
#r:= CASE WHEN #g = g.`user` THEN #r +1 ELSE 1 END rownum,
#g:= g.`user` user_group
FROM sn.sn_graph_reduced g
CROSS JOIN (SELECT #g:=0,#r:=0) t2
ORDER BY `user` , RAND()
) t
WHERE rownum <= 100
However, the above code snippet returns the row number, and since the records are RANDOMLY sampled, the row numbers are not incremental.
What I need is a simple counter (1,2,3....) for each row returned.
thanks
Try putting the variable outside of the inline view:
SELECT t.*,
#r:= CASE WHEN #t = t.`user` THEN #r +1 ELSE 1 END rownum,
#t:= t.`user` user_group
FROM (
SELECT CONCAT(' ',g.node1,' ',g.node2), g.`user`
FROM sn.sn_graph_reduced g
ORDER BY `user` , RAND()
) t
CROSS JOIN (SELECT #t:=0,#r:=0) t2
where rownum <= 100
the method for incrementing row number doesn't cope with RAND() directly, so use values from rand() as a column. Also initiate #g as '' not zero and then you need a final ORDER BY.
SELECT
*
FROM (
SELECT
CONCAT(' ', g.node1, ' ', g.node2) AS node_concat
, #r:= IF(#g = g.`user`, #r + 1, 1) AS rownum
, #g:= g.`user` AS user_group
FROM (
SELECT *, rand() AS R FROM sn_graph_reduced
) g
CROSS JOIN ( SELECT #g:= '' ,#r:= 1 ) t2
ORDER BY
`user`
, R
) t
WHERE rownum <= 100
ORDER BY
user_group
, rownum
;
see: This SQLfiddle