n-th row in PostgreSQL for p-quantile - postgresql

I'm trying to fetch the n-th row of a query result. Further posts suggested the use of OFFSET or LIMIT but those forbid the use of variables (ERROR: argument of OFFSET must not contain variables). Further I read about the usage of cursors but I'm not quite sure how to use them even after reading their PostgreSQL manpage. Any other suggestions or examples for how to use cursors?
My main goal is to calculate the p-quantile of a row and since PostgreSQL doesn't provide this function by default I have to write it on my own.
Cheers

The following returns the 5th row of a result set:
select *
from (
select <column_list>,
row_number() over (order by some_sort_column) as rn
) t
where rn = 5;
You have to include an order by because otherwise the concept of "5th row" doesn't make sense.
You mention "use of variable" so I'm not sure what you are actually trying to achive. But you should be able to supply the value 5 as a variable for this query (or even a sub-select).
You might also want to dig further into windowing functions. Because with that you could e.g. do a sum() over the 3 rows before the current row (or similar constructs) - which could also be useful for you.

if you would like to get 10th record, below query also work fine.
select * from table_name order by sort_column limit 1 offset 9
OFFSET simply skip that many rows before beginning to return rows as mentioned in LIMIT clause.

Related

Getting the total number of records in a single knexjs query when using the limit() method

I use knexjs and postgresql. Is it possible in knexjs to get the total of records from the same query in which the limit is used?
For example:
knex.select().from('project').limit(50)
Is it possible to somehow get the total number of records in the same query if there are more than 50?
The question arose due to the fact that my query is much more complex, which uses a lot of subqueries and conditions, and I would not like to make this query twice to get the data in one query and the total number of records (I use the .count() method) from another.
I do not know your obscurification manager (knexjs?) but I would think you should be able to add the window version of the count() function to your select list. In plain SQL something like: Where ... represents your current select list. (see demo)
select ..., count(*) over() total_rows
from project
limit 5;
This works because the window count function counts all rows selected, after all rows selected, but before the LIMIT clause is applied. Note: This adds a column to the result set with the same value in every row.

What does ORDER BY within OVER() window function mean in postgresql?

I am trying to understand how the ORDER BY clause in the OVER() window function is different from ORDER BY clause in generic SQL.
I was solving the following problem: https://www.pgexercises.com/questions/aggregates/nummembers.html
Produce a monotonically increasing numbered list of members (including guests),
ordered by their date of joining. Remember that member IDs are not guaranteed to be sequential.
The following query is one of the accepted solutions:
SELECT COUNT(*) OVER(ORDER by joindate), firstname, surname FROM cd.members;
As per my understanding, since we are not supplying a PARTITION BY clause in the OVER() function, all the rows in cd.members table form one big partition (let's call it X). When the window function runs, it should order X by joindate, and then COUNT(*) on X would return the number of rows in X which is just the number of rows in cd.members.
But this understanding is incorrect. The 'Answers and Discussion' accompanying the aforementioned problem states:
Since we define an order for the window function, for any given row the window is: start of the dataset -> current row.
The PG documentation on window function states:
You can also control the order in which rows are processed by window functions using ORDER BY within OVER. (The window ORDER BY does not even have to match the order in which the rows are output.)
What I cannot comprehend is why will ORDER BY inside the OVER() stop at the current row? Could you please elaborate how this is working?
Thank you for reading through.
I don't know what to add beyond what the docs (same page as you already linked to) already say:
By default, if ORDER BY is supplied then the frame consists of all
rows from the start of the partition up through the current row, plus
any following rows that are equal to the current row according to the
ORDER BY clause.
I don't now if this required by the SQL standard, but it certainly seems reasonable. Why specify an ORDER BY if you expect it to have no observable effect?

PostgreSQL Rolling Standard Deviation over time in single query

This may be an easily solvable question but I can't see an immediate solution. I am calling a PostgreSQL function which returns multiple columns, 2 of which are relevant to this question - a date column & a numeric field of return values. An example of the function call would be
SELECT curr_date, return_val
FROM schema.function_name($1,$2);
With example output such as
"2014-07-31";0.003767
"2014-08-07";-0.028531
"2014-08-14";0.020051
"2014-08-21";-0.003541
"2014-08-28";0.007766
"2014-09-04";-0.021926
"2014-09-11";0.026330
"2014-09-18";0.008137
"2014-09-25";-0.033303
"2014-10-02";0.030100
"2014-10-09";-0.012116
"2014-10-16";-0.017148
So on, so forth. The data will always return from this function with the dates ascending. What I would like to do is to use Postgres's stddev_samp function on every row, but only considering the return_value's from that row's date back in time. Something like:
SELECT curr_date, return_val,
--stddev_samp(return_val) where curr_date <= curr_date of current row
FROM schema.function_name($1,$2);
Naturally, if I calculated the sample deviation of the return_value's from 2014-07-31 to 2014-10-02 in the sample provided, it would differ slightly to calculating it using the result set from 2014-07-31 to any other date present. I know I could probably write another function which takes a numeric array as input and returns the standard deviation as output, and then call this in my query above, but I'm hoping someone may have a simpler approach which I'm just currently not seeing. If any other information is required, feel free to ask. I'm using version 10.7.
demo:db<>fiddle
Using window functions:
SELECT
stddev_samp(return_val) OVER(ORDER BY curr_date)
FROM
mytable

Accessing current row value with lag function

I want to calculate the difference between the previous and the current column and make it a new column named increase. For this, I'm using the lag window function. The value of the first column is not defined since no previous column exists. I know that a 3rd parameter specifies the default value. However, it depends. For the first row, I want to use the value of another column e.g. the one of count from that current row. This assumes that 0 is increased to count for the first row which is what I need. Specifying the column name as 3rd argument for the lag function does not work correctly and neither does using 0. How can it be done? I'm getting strange results such as quite a random result or even negative numbers.
SELECT *, mycount - lag(mycount, 1) OVER (ORDER BY id, messtime ASC) AS increase FROM measurements;
Window functions cannot be nested either:
ERROR: window function calls cannot be nested
There is another issue with your query: So far your results are in random order, so you may think you are seeing problems that don't exist.
Add ORDER BY id, messtime to your query to see the rows in order. Now you can compare one row with its predecessor directly. Are there still issues? If so, which exactly?
SELECT *, "count" - lag("count", 1) OVER (ORDER BY id, messtime) AS increase
FROM measurements
ORDER BY id, messtime;
COUNT is a reserved word in SQL. It seems the DBMS thinks you want to nest COUNT and LAG somehow.
Use another column name or use quotes for the column:
SELECT *, "count" - lag("count", 1) OVER

running total using windows function in sql has same result for same data

From every references that I search how to do cumulative sum / running total. they said it's better using windows function, so I did
select grandtotal,sum(grandtotal)over(order by agentname) from call
but I realize that the results are okay as long as the value of each rows are different. Here is the result :
Is There anyway to fix this?
You might want to review the documentation on window specifications (which is here). The default is "range between" which defines the range by the values in the row. You want "rows between":
select grandtotal,
sum(grandtotal) over (order by agentname rows between unbounded preceding and current row)
from call;
Alternatively, you could include an id column in the sort to guarantee uniqueness and not have to deal with the issue of equal key values.