Compute average of a column, excpet for the first row - sql

I'm trying to compute some queries, with the aggregates functions.
The problem is I'm not able to compute the average of the column, without the first value.
example
_myColumn_
10
15
20
Final average: (10 + 15 + 20) / 3 = 15
What I want is: (15 + 20) / 2 = 12.5
This is the code I've tried without success
select avg(age) from testing
except
select avg(age) from testing
limit 1

First use OFFSET clause to skip the first row. (You should really ensure the order with an ORDER BY clause.) Then compute the AVG on that result:
select avg(age)
from
(
select age from testing
offset 1
) dt
Or, if the first row is expected to be the one with the lowest age:
select (sum(age) - min(age)) / (count(*) - 1)
from testing

There is no such thing as a "first" row in SQL, because tables represent unordered sets. A column is needed to specify the ordering.
Let me assume you mean the row with the smallest value. This is a little tricky, but you can use row_number():
select avg(age)
from (select t.*, row_number() over (order by age) as seqnum
from t
) t
where seqnum > 1;

I'd propose use something like this(some field Should be UNIQUE, for example ID if you have one)
SELECT AVG(age) FROM testing WHERE ID NOT IN
(SELECT ID FROM testing ORDER BY ??SOMETHING HERE?? limit 1)

Related

Teradata SQL Query to filter only those rows who has entry for all period ids

I have a dataset with 3 columns (ID, YYYYMM, sales). I wanted to have only those IDs who record is present for every YYYYMM (201909 to 202003).
I want to have the date at ID and YYYYMM level itself. I dont want to use group by and have the dataset reduced to one ID row.
Hmmm . . . I think this does what you want:
select t.*
from mytable t
where yyyymm >= 201909 and
yyyymm <= 202003
qualify count(*) over (partition by id) = 6;
You could use window functions and a qualify clause:
select t.*
from mytable t
qualify count(*) over(partition by id)
= 1 + max(floor(yyyymm / 100) * 12 + (yyymmm mod 100)) over()
- min(floor(yyyymm / 100) * 12 + (yyymmm mod 100)) over()
The qualify clause counts how many records exist for the current id, and compares it to the overal count of yyyymmdds, which can be computed by substracting its max and min values (this assumes that this is a numeric value, as it looks).

get graph data from large table using nth_value window function in postgres

I'm trying to plot a graph of the data from a large table. I can get all of it easily by doing basically
select id, value from data order by value desc;
but that yields me about a hundred thousand rows. About 50 are enough for my purpose, so I want to basically have the equivalent of a step function. Searching turned up "nth_value" as the appropriate window function that probably does what I need, but I couldn't find examples on how to actually use it for this purpose.
Or maybe there's a better way even?
(I'm using PostgreSQL 9.6 in case it matters)
I would be very wary of using row_number() without an order by clause.
One way to phrase this is:
select id, value
from (select d.*,
row_number() over (order by id) as n,
count(*) over () as cnt
from data d
) d
where n % floor(cnt / 50) = 0;
This will typically return either 50 or 51 rows. If you want exactly 50 rows, you can add fetch first 50 rows.
You want only the first 50 rows?
select id, value
from data
order by value desc
limit 50;
Every 50th row?
select id, value
from (select id, value, row_number() over () as n
from data) d
where n % 50 = 0
You can choose whatever ordering you want in the OVER clause, e.g. ROW_NUMBER() OVER (ORDER BY value DESC)
Every nth row to get 50 results?
select id, value
from (select id, value, row_number() over () as n
from data) d
where n % ((select count(*) from d) / 50) = 0
Working example on dbfiddle

How to skip/offset rows in Oracle database?

I am writing a very simple query for an Oracle DB (version 9).
Somehow I can get first 5 rows:
select * from cities where rownum <= 5
But skipping 5 rows returns an empty result:
select * from cities where rownum >= 5
Using:
Oracle SQL Developer
Oracle DB version 9
Why is the second query returning an empty result?
In Oracle Database 12c (release 1) and above, you can do this very simple, for skip 5 rows:
SELECT * FROM T OFFSET 5 ROWS
and for skip 5 rows and take 15 rows:
SELECT * FROM T OFFSET 5 ROWS FETCH NEXT 15 ROWS ONLY
You can use the following query to skip the first not n of rows.
select * from (
select rslts.*, rownum as rec_no from (
<<Query with proper order by (If you don't have proper order by you will see weird results)>>
) rslts
) where rec_no > <<startRowNum - n>>
The above query is similar to pagination query below.
select * from (
select rslts.*, rownum as rec_no from (
<<Query with proper order by (If you don't have proper order by you will see weird results)>>
) rslts where rownum <= <<endRowNum>>
) where rec_no > <<startRowNum>>
Your cities query:
select * from (
select rslts.*, rownum as rec_no from (
select * from cities order by 1
) rslts
) where rec_no > 5 <<startRowNum>>
Note: Assume first column in cities table is unique key
Oracle increments rownum each time it adds a row to the result set. So saying rownum < 5 is fine; as it adds each of the first 5 rows it increments rownum, but then once ruwnum = 5 the WHERE clause stops matching, no more rows are added to the result, and though you don't notice this rownum stops incrementing.
But if you say WHERE rownum > 5 then right off the bat, the WHERE clause doesn't match; and since, say, the first row isn't added to the result set, rownum isn't incremented... so rownum can never reach a value greater than 5 and the WHERE clause can never match.
To get the result you want, you can use row_number() over() in a subquery, like
select *
from (select row_number() over() rn, -- other values
from table
where -- ...)
where rn > 5
Update - As noted by others, this kind of query only makes sense if you can
control the order of the row numbering, so you should really use row_number() over(order bysomething) where something is a useful ordering key in deciding which records are "the first 5 records".
rownum is being increased only when a row is being output, so this type of condition won't work.
In any case, you are not ordering your rows, so what's the point?
Used row_number() over (order by id):
select * from
(select row_number() over (order by id) rn, c.* from countries c)
where rn > 5
Used ROWNUM:
select * from
(select rownum rn, c.* from countries c)
where rn > 5
Important note:
Using alias as countries c instead of countries is required! Without, it gives an error "missing expression"
Even better would be:
select * from mytab sample(5) fetch next 1 rows only;
Sample clause indicates the probability of each row getting picked up in the sampling process. FETCH NEXT clause indicates the number of rows you want to select.
With this code, you can query your table with skip and take.
select * from (
select a.*, rownum rnum from (
select * from cities
) a
) WHERE rnum >= :skip + 1 AND rnum <= :skip + :take
This code works with Oracle 11g. With Oracle 12, there is already a better way to perform this queries with offset and fetch

How to use ROWNUM for a maximum and another minimum ordering in ORACLE?

Currently i am trying to output the top row for 2 condition. One is max and one is min.
Current code
Select *
from (MY SELECT STATEMENT order by A desc)
where ROWNUM <= 1
UPDATE
I am now able to do for both condition. But i need the A to be the highest, if same then check for the B lowest.
E.g Lets say there is 2 rows, Both A is 100 and B is 50 for one and 60 for other.
In this case the 100:50 shld be choose because A is same then B is lowest.
E.g
Lets say there is 2 rows, A is 100 for one and 90 for other, since one is higher no need to check for B.
I tried using max and min but this method seems to work better, any suggestions
Well, after your clarification, you are looking for one record. With Max A. And the smallest B, in case there is more than one record with MAX A. This is simply:
Select *
from (MY SELECT STATEMENT order by A desc, B)
where ROWNUM = 1;
This sorts by A descending first, so you get all maximal A records first. Then it sorts by B, so inside each A group you get the least B first. This gives you the desired A record first, no matter if the found A is unique or not.
or avoid the vagaries of rownun and go for row_number() instead:
SELECT
*
FROM (
SELECT
*
, ROW_NUMBER (ORDER BY A DESC) adesc
, ROW_NUMBER (ORDER BY B ASC) basc
FROM SomeQuery
)
WHERE adesc = 1
OR basc = 1
footnote: select * is a convenience only, please replace with the actual columns required along with table names etc.
Try this if that works
Select *
from (MY SELECT STATEMENT order by A desc)
where ROWNUM <= 1
union
Select *
from (MY SELECT STATEMENT order by A asc)
where ROWNUM <= 1
SELECT * FROM
(Select foo.*, 0 as union_order
from (MY SELECT STATEMENT order by A desc) foo
where ROWNUM <= 1
UNION
Select foo.*, 1
from (MY SELECT STATEMENT order by B asc) foo
where ROWNUM <= 1)
ORDER BY
union_order

Find the top 5 MAX() values from an SQL table and then performi an AVG() on that table without them

I want to be able to perform an avg() on a column after removing the 5 highest values in it and see that the stddev is not above a certain number. This has to be done entirely as a PL/SQL query.
EDIT:
To clarify, I have a data set that contains values in a certain range and tracks latency. I want to know whether the AVG() of those values is due to a general rise in latency, or due to a few values with a very high stddev. I.e - (1, 2, 1, 3, 12311) as opposed to (122, 124, 111, 212). I also need to achieve this via an SQL query due to our monitoring software's limitations.
You can use row_number to find the top 5 values, and filter them out in a where clause:
select avg(col1)
from (
select row_number() over (order by col1 desc) as rn
, *
from YourTable
) as SubQueryAlias
where rn > 5
select column_name1 from
(
select column_name1 from table_name order by nvl(column_name,0) desc
)a
where rownum<6
(the nvl is done to omit the null value if there is/are any in the column column_name)
Well, the most efficient way to do it would be to calculate (sum(all values) - sum(top 5 values)) / (row_count - 5)
SELECT SUM(val) AS top5sum FROM table ORDER BY val DESC LIMIT 5
SELECT SUM(val) AS allsum FROM table
SELECT (COUNT(*) - 5) AS bottomCount FROM table
The average is then (allsum - top5sum) / bottomCount
First, get the MAX 5 values:
SELECT TOP 5 RowId FROM Table ORDER BY Column
Now use this in your main statement:
SELECT AVG(Column) FROM Table WHERE RowId NOT IN (SELECT TOP 5 RowId FROM Table ORDER BY Column)