couchbase: how to add sr number to the results in asc order - couchbase

I want to add one column in the first which shows the sr.no (sequence number) in ascending order.
example: (here the sequence number will not be order, rather follow the order of plan_year)
SELECT ROW_NUMBER() OVER(),
plan_name,
plan_year
FROM `prod-fliptrx-app`
WHERE type = 'something'
ORDER BY plan_year DESC
so how to ensure in the above command i see the seq number in asc order irrespective of the ORDER BY attribute in the end

ROW_NUMBER() OVER() always increase number. As you don't have any ORDER BY specified in ROW_NUMBER(), it assigns seq no number but your ORDER BY clause of query changes order. As projection is done before query ORDER BY.
You can generate ROW_NUMBER() on plan_year DESC and sort by row_number like below:
SELECT ROW_NUMBER() OVER( ORDER BY plan_year DESC) AS rnum,
plan_name,
plan_year
FROM `prod-fliptrx-app`
WHERE type = 'something'
ORDER BY rnum;

Related

Order by highest value alternating with lowest value

I currently need to order data by highest value down, and then lowest value up, in between.
My Query is close, but doesn't quite order by largest down, though it is inserting the lowest in between:
DEMO Fiddle
select users.*
from users CROSS JOIN (select #even := 0, #odd := 0) param
order by
IF(score > 1, 2*(#odd := #odd + 1), 2*(#even := #even + 1) + 1),
score DESC;
Current Results
Email Score
----- --------
foo1#gmail.com 42
foo5#gmail.com 1
foo2#gmail.com 49
foo6#gmail.com 0
foo3#gmail.com 37
foo4#gmail.com 7
foo#gmail.com 22
Desired Results
Email Score
----- --------
foo2#gmail.com 49
foo6#gmail.com 0
foo1#gmail.com 42
foo5#gmail.com 1
foo3#gmail.com 37
foo4#gmail.com 7
foo#gmail.com 22
You can achieve using MySQL but avoid such complex SQL statements as the same can be achieved using programming language very easily.
SET #totalRows := (CASE WHEN (SELECT COUNT(*) FROM users) IS NULL THEN 0 ELSE (SELECT COUNT(*) FROM users) END);
PREPARE stmt1 FROM '(SELECT t.* FROM (SELECT ROW_NUMBER() OVER (ORDER BY score DESC) AS row_num, email, score FROM users UNION ALL SELECT ROW_NUMBER() OVER (ORDER BY score ASC) AS row_num, email, score FROM users) AS t ORDER BY t.row_num, t.score DESC LIMIT 0,?)';
EXECUTE stmt1 USING #totalRows;
Here is the explanation to achieve it:
Set variable #totalRows contains total rows in users table as that many rows will be displayed as a final result set.
Used ROW_NUMBER() function of MySQL to set ordering based on SOCRE field DESCENDING and ASCENDING for another result set.
Combined both the result set using UNION ALL statement of MySQL
Add the LIMIT keyword to make sure the final result must have a total number of rows that should not exceed #totalRows variable.
As in MySQL LIMIT statement we can't pass a dynamic value at a query level. I used the approach of prepare a statement.
You can ignore row_num column I used as final result set.
Hope my solution will help you.
For MySql 8.0+ you can use ROW_NUMBER() window function:
SELECT email, score
FROM (
SELECT *,
ROW_NUMBER() OVER (ORDER BY score DESC) rn1,
ROW_NUMBER() OVER (ORDER BY score ASC) rn2
FROM users
) t
ORDER BY LEAST(rn1, rn2), rn1;
For previous versions you can simulate ROW_NUMBER() with correlated subqueries (with the cost of poor performance for large datasets):
SELECT email, score
FROM (
SELECT u1.*,
(SELECT COUNT(*) FROM users u2 WHERE u2.score > u1.score) rn1,
(SELECT COUNT(*) FROM users u2 WHERE u2.score < u1.score) rn2
FROM users u1
) t
ORDER BY LEAST(rn1, rn2), rn1;
See the demo.

Distinct entries from the set

I am using the below query on the above database table but unable to get the distinct value. Help will be appreciated
SELECT DISTINCT doctor_user_id, doctor_name, score, time_in_seconds FROM basket_game_master WHERE game_id='$game_id' ORDER BY score DESC, time_in_seconds ASC LIMIT $limit
The goal is to retrieve the doctor name with unique doctor_user_id who have more score with less time_in_seconds
You can use ROW_NUMBER():
SELECT doctor_user_id, doctor_name, score, time_in_seconds
FROM (SELECT bgm.*,
ROW_NUMBER() OVER (PARTITION BY doctor_user_id ORDER BY score DESC, time_in_seconds ASC) as seqnum
FROM basket_game_master bgm
WHERE game_id = ?
) mgm
WHERE seqnum = 1
ORDER BY score DESC, time_in_seconds ASC
LIMIT ?;
Note the use of ? for the parameters. Do not munge the query string with literal values! That poses a risk for SQL injections and for hard-to-debug syntax errors.

Select latest record with date and time column with group by clause in mysql

I have this table from which I have to select the latest row on the basis of date and time column for each checkpost
I have tried the following queries but not returning the latest data for each checkpost.
SELECT checkpost_id,current_rate,date,time FROM revisionrates
WHERE date IN (SELECT max(date) FROM revisionrates GROUP BY checkpost_id)
The expected output is
You can use window functions:
select rr.*
from (select rr.*,
row_number() over (partition by checkpost_id order by date desc, time desc) as seqnum
from revisionrates rr
) rr
where seqnum = 1;
This requires MySQL 8.0. In earlier versions of MySQL, this is a bit trickier, but one method uses tuples
select rr.*
from rr
where (date, time) in (select rr2.date, rr2.time
from revisionrates rr2
where rr2.checkpoint_id = rr.checkpoint_id
order by rr2.date desc, rr2.time desc
limit 1
);

How can I RANK from AVG sql?

I'm having trouble retrieving the rankings from a single line that has some uuid from that:
SELECT uuid , AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average
from elo_ranked group by uuid
order by AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 desc
limit 3
I specify that the above function works and has the expected result.
Is this what you want?
SELECT uuid, AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average ,
RANK() OVER (ORDER BY AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 DESC) as ranking
FROM elo_ranked
GROUP BY uuid
ORDER BY AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 desc
LIMIT 3;
EDIT:
To rank a specific user, use a subquery:
SELECT u.*
FROM (SELECT uuid, AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average ,
RANK() OVER (ORDER BY AVG(nodebuff+debuff+archer+builduhc+uhc+gapple)/6 DESC) as ranking
FROM elo_ranked
GROUP BY uuid
) u
WHERE uuid = ?;
Also, I'm not sure if you need the aggregation. That would only be needed if a user had multiple rows in the elo_ranked table. If not needed, then you should use:
SELECT u.*
FROM (SELECT uuid, (nodebuff+debuff+archer+builduhc+uhc+gapple)/6 as Average ,
RANK() OVER (ORDER BY (nodebuff+debuff+archer+builduhc+uhc+gapple)/6 DESC) as ranking
FROM elo_ranked
) u
WHERE uuid = ?;
The GROUP BY has a lot of overhead, so this should be faster (unless MySQL has sophisticated optimizations to avoid the aggregation when grouping by a primary key).

How can i get just the latest 2 records on each group when using GROUP_CONCAT?

SELECT id, GROUP_CONCAT(type SEPARATOR '/') as types FROM `sems` GROUP by year
I just want to get the 2 latest record on each group
If you are running MySQL 8.0, you can use row_number() for this. You need an ordering column to define the latest record, I assumed ordering_id:
select id, group_concat(type order by rn separator '/') types
from (
select id, type, row_number() over(partition by id order by ordering_id desc) rn
from sems
) t
where rn <= 2
group by id
In earlier versions, one option is to filter with a subquery:
select id, group_concat(type order by rn separator '/') types
from sems s
where s.ordering_id >= (
select s1.ordering_id
from sems s1
where s1.id = s.id
order by s1.ordering_id desc
limit 2
)
group by id
This assumes that (id, ordering_id) tuples are unique. If not, and there are ties in the top 2, all related records will be taken into account.
If your data is not too numerous, you can use:
SELECT id,
SUBSTRING_INDEX(GROUP_CONCAT(type ORDER BY ? DESC SEPARATOR '/'), '/', -2) as types
FROM `sems`
GROUP by year;.
The ? is for the column used to define "latest"