rank function with limits in postgresql - postgresql

select * from rankings;
students | stu_id | card_id
----------+--------+---------
Charlie | 11 | 1
Shakira | 22 | 2
Selena | 33 | 3
Ross | 44 | 4
Chandler | 55 | 5
James | 66 | 6
Kylie | 77 | 7
Here is the table kindly tell me how we can apply the rank function in it with Postgresql?

Related

Reformatting table in SQL

I have a table in sql
Table Link
is there a way to reformat this table with contract_kind as rows and percentile values as columns without me having to create 4 tables with where clauses and joining them. Using Postgres.
TLDR: just use the crosstab function as per documentation
Long reply:
I recreated a similar case with
create table test (id int, contract_kind text, percentile int, cut_off_time float);
insert into test values
(1,'TEMPLATE',25,1.91),
(2,'TEMPLATE',50,51.93),
(3,'TEMPLATE',75,158.41),
(4,'TEMPLATE',90,343.01),
(5,'TEMPLATE_EDITABLE',25,26),
(6,'TEMPLATE_EDITABLE',50,27),
(7,'TEMPLATE_EDITABLE',75,28),
(8,'TEMPLATE_EDITABLE',90,29),
(9,'UPLOAD_EDITABLE',25,10),
(10,'UPLOAD_EDITABLE',50,20),
(11,'UPLOAD_EDITABLE',75,30),
(12,'UPLOAD_EDITABLE',90,40),
(13,'UPLOAD_SIGN',25,40),
(14,'UPLOAD_SIGN',50,77),
(15,'UPLOAD_SIGN',75,99),
(16,'UPLOAD_SIGN',90,133);
result:
id | contract_kind | percentile | cut_off_time
----+-------------------+------------+--------------
1 | TEMPLATE | 25 | 1.91
2 | TEMPLATE | 50 | 51.93
3 | TEMPLATE | 75 | 158.41
4 | TEMPLATE | 90 | 343.01
5 | TEMPLATE_EDITABLE | 25 | 26
6 | TEMPLATE_EDITABLE | 50 | 27
7 | TEMPLATE_EDITABLE | 75 | 28
8 | TEMPLATE_EDITABLE | 90 | 29
9 | UPLOAD_EDITABLE | 25 | 10
10 | UPLOAD_EDITABLE | 50 | 20
11 | UPLOAD_EDITABLE | 75 | 30
12 | UPLOAD_EDITABLE | 90 | 40
13 | UPLOAD_SIGN | 25 | 40
14 | UPLOAD_SIGN | 50 | 77
15 | UPLOAD_SIGN | 75 | 99
16 | UPLOAD_SIGN | 90 | 133
(16 rows)
Now to use the crosstab you need to create the tablefunc extension.
create extension tablefunc;
and then you can use it to pivot the data
select * from
crosstab('select percentile, contract_kind, cut_off_time from test order by 1,2')
as ct(percentile int, template float, template_editable float, upload_editable float, upload_sing float);
result
percentile | template | template_editable | upload_editable | upload_sing
------------+----------+-------------------+-----------------+-------------
25 | 1.91 | 26 | 10 | 40
50 | 51.93 | 27 | 20 | 77
75 | 158.41 | 28 | 30 | 99
90 | 343.01 | 29 | 40 | 133
(4 rows)

postgrest retreive ranked results

I made a game, with level and scores saved into an sql table like this :
create table if not exists api.scores (
id serial primary key,
pseudo varchar(50),
level int,
score int,
created_at timestamptz default CURRENT_TIMESTAMP
);
I want to display the scores in the ui with the rank of each score, based on the score column, ordered by desc.
Here is a sample data :
id | pseudo | level | score | created_at
----+----------+-------+-------+-------------------------------
1 | test | 1 | 1 | 2020-05-01 11:25:20.446402+02
2 | test | 1 | 1 | 2020-05-01 11:28:11.04001+02
3 | szef | 1 | 115 | 2020-05-01 15:45:06.201135+02
4 | erg | 1 | 115 | 2020-05-01 15:55:19.621372+02
5 | zef | 1 | 115 | 2020-05-01 16:14:09.718861+02
6 | aa | 1 | 115 | 2020-05-01 16:16:49.369718+02
7 | zesf | 1 | 115 | 2020-05-01 16:17:42.504354+02
8 | zesf | 2 | 236 | 2020-05-01 16:18:07.070728+02
9 | zef | 1 | 115 | 2020-05-01 16:22:23.406013+02
10 | zefzef | 1 | 115 | 2020-05-01 16:23:49.720094+02
Here is what I want :
id | pseudo | level | score | created_at | rank
----+----------+-------+-------+-------------------------------+------
31 | zef | 7 | 730 | 2020-05-01 18:40:42.586224+02 | 1
50 | Cyprien | 5 | 588 | 2020-05-02 14:08:39.034112+02 | 2
49 | cyprien | 4 | 438 | 2020-05-01 23:35:13.440595+02 | 3
51 | Cyprien | 3 | 374 | 2020-05-02 14:13:41.071752+02 | 4
47 | cyprien | 3 | 337 | 2020-05-01 23:27:53.025475+02 | 5
45 | balek | 3 | 337 | 2020-05-01 19:57:39.888233+02 | 5
46 | cyprien | 3 | 337 | 2020-05-01 23:25:56.047495+02 | 5
48 | cyprien | 3 | 337 | 2020-05-01 23:28:54.190989+02 | 5
54 | Cyzekfj | 2 | 245 | 2020-05-02 14:14:34.830314+02 | 9
8 | zesf | 2 | 236 | 2020-05-01 16:18:07.070728+02 | 10
13 | zef | 1 | 197 | 2020-05-01 16:28:59.95383+02 | 11
14 | azd | 1 | 155 | 2020-05-01 17:53:30.372793+02 | 12
38 | balek | 1 | 155 | 2020-05-01 19:08:57.622195+02 | 12
I want to retreive the rank based on the full table whatever the result set.
I'm using the postgrest webserver.
How do I do that ?
You are describing window function rank():
select t.*, rank() over(order by score desc) rnk
from mytable t
order by score desc

Sort using auxiliary fields, start and end

In PostgreSQL, what is the best way to sort records using start and end fields in a generic way, without the need to include in the query the first record (where start_id=3)?
Example table:
+-------+----------+--------+--------+
| FK_ID | START_ID | END_ID | STRING |
+-------+----------+--------+--------+
| 77 | 1 | 9 | E |
| 82 | 5 | 2 | A |
| 77 | 7 | 1 | I |
| 77 | 3 | 7 | W |
| 82 | 9 | 5 | Q |
| 77 | 9 | 5 | X |
| 82 | 2 | 7 | G |
+-------+----------+--------+--------+
Sorted where FK_ID = 77:
+----+---+---+---+
| 77 | 3 | 7 | W |
| 77 | 7 | 1 | I |
| 77 | 1 | 9 | E |
| 77 | 9 | 5 | X |
+----+---+---+---+
Sorted where FK_ID = 82:
+----+---+---+---+
| 82 | 9 | 5 | Q |
| 82 | 5 | 2 | A |
| 82 | 2 | 7 | G |
+----+---+---+---+
Result query sequence:
+-------+----------+
| FK_ID | SEQUENCE |
+-------+----------+
| 82 | QAG |
| 77 | WIEX |
+-------+----------+
I do not think this is the most efficient way but you can try with a recursive CTE
WITH RECURSIVE path AS (
SELECT * FROM myTable AS t1 WHERE NOT EXISTS(
SELECT 1 FROM myTable AS t2 WHERE t1.fk_id = t2.fk_id AND t2.end_id = t1.start_id
) ORDER BY start_id LIMIT 1
UNION ALL
SELECT myTable.* FROM myTable JOIN path ON path.end_id = myTable.start_id
)
SELECT fk_id,array_to_string(array_agg(string)) FROM path GROUP BY fk_id

Select rows by one column value should only be repeat N times

My table is:
id sub_id datetime resource
---|-----|------------|-------
1 | 10 | 04/03/2009 | 399
2 | 11 | 04/03/2009 | 244
3 | 10 | 04/03/2009 | 555
4 | 10 | 03/03/2009 | 300
5 | 11 | 03/03/2009 | 200
6 | 11 | 03/03/2009 | 500
7 | 11 | 24/12/2008 | 600
8 | 13 | 01/01/2009 | 750
9 | 10 | 01/01/2009 | 760
10 | 13 | 01/01/2009 | 570
11 | 11 | 01/01/2009 | 870
12 | 13 | 01/01/2009 | 670
13 | 13 | 01/01/2009 | 703
14 | 13 | 01/01/2009 | 705
I need to select for each sub_id only 2 times
Result would be:
id sub_id datetime resource
---|-----|------------|-------
1 | 10 | 04/03/2009 | 399
3 | 10 | 04/03/2009 | 555
5 | 11 | 03/03/2009 | 200
6 | 11 | 03/03/2009 | 500
8 | 13 | 01/01/2009 | 750
10 | 13 | 01/01/2009 | 570
How can I achieve this result in postgres ?
Use the window function row_number():
select id, sub_id, datetime, resource
from (
select *, row_number() over (partition by sub_id order by id)
from my_table
) s
where row_number < 3;
look at the order column (I use id to match your sample):
t=# with data as (select *,count(1) over (partition by sub_id order by id) from t)
select id,sub_id,datetime,resource from data where count <3;
id | sub_id | datetime | resource
----+--------+------------+----------
1 | 10 | 2009-03-04 | 399
3 | 10 | 2009-03-04 | 555
2 | 11 | 2009-03-04 | 244
5 | 11 | 2009-03-03 | 200
8 | 13 | 2009-01-01 | 750
10 | 13 | 2009-01-01 | 570
(6 rows)

org mode - simplify table sum formula of multiple column

Now I need 5 formula for sum of each column, it works fine but I wish it can be simplified to one formula. Is it possible?
|----+----+----+-----+----|
| a | b | c | d | e |
|----+----+----+-----+----|
| 1 | 2 | 3 | 4 | 5 |
| 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 |
|----+----+----+-----+----|
| 34 | 38 | 42 | 160 | 50 |
|----+----+----+-----+----|
#+TBLFM: #>$5=vsum(#2$5..#-1$5)::#>$4=vsum(#2$1..#-1$4)::#>$3=vsum(#2$3..#-1$3)::#>$2=vsum(#2$2..#-1$2)::#>$1=vsum(#2$1..#-1$1)
This should work:
|----+----+----+----+----|
| a | b | c | d | e |
|----+----+----+----+----|
| 1 | 2 | 3 | 4 | 5 |
| 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 |
| 16 | 17 | 18 | 19 | 20 |
|----+----+----+----+----|
| 34 | 38 | 42 | 46 | 50 |
|----+----+----+----+----|
#+TBLFM: #>$1..#>$5=vsum(#2$0..#-1$0)
$0 on the RHS is the current column.