I have to fetch the first and last row of the table in Toad.
I have used the following query
select * from grade_master where rownum=(select max(rownum) from grade_master)
select * from grade_master where rownum=1
The second query works to fetch the first row. but the first not working. Anyone please help me.
Thanks in advance
Such request makes sense if you specify sort order of the results - there are no such things in database as "first" and "last" rows if sort order is not specified.
SQL> with t as (
2 select 'X' a, 1 b from dual union all
3 select 'C' , 2 from dual union all
4 select 'A' a, 3 b from dual
5 )
6 select a, b, decode(rn, 1, 'First','Last')
7 from (
8 select a, b, row_number() over(order by a) rn,
9 count(*) over() cn
10 from t
11 )
12 where rn in (1, cn)
13 order by rn
14 /
A B DECOD
- ---------- -----
A 3 First
X 1 Last
In oracle the data is not ordered until you specify the order in you sql statement.
So when you do:
select * from grade_master
oracle will give the rows in anyway it want wants.
OTOH if you do
select * from grade_master order by id desc
Then oracle will give the rows back ordered by id descending.
So to get the last row you could do this:
select *
from (select * from grade_master order by id desc)
where rownum = 1
The rownum is determined BEFORE the "order by" clause is assessed, so what this query is doing is ordering the rows descending (the inside query) and then giving this ordered set to the outer query. The outer gets the first row of the set then returns it.
Related
I have the following result, which is easily calculated in Excel, but how to do it in Oracle, the result is the following, based on a previous select and comes from one column,
Result from select Expected result
1.62590
0.60989 0.991620151
0.83859 0.831562742
the result is based on 1.62590 * 0.60989 = 0.991620151,
1.62590 * 0.60989 * 0.83859 = 0.831562742
You can use:
SELECT id,
result,
EXP(SUM(LN(result)) OVER (ORDER BY id)) AS expected
FROM table_name;
Note: Use any other column instead of id to give the appropriate ordering or, if your rows are already ordered, use the ROWNUM pseudo-column instad of id.
Which, for the sample data:
CREATE TABLE table_name (id, Result) AS
SELECT 1, 1.62590 FROM DUAL UNION ALL
SELECT 2, 0.60989 FROM DUAL UNION ALL
SELECT 3, 0.83859 FROM DUAL;
Outputs:
ID
RESULT
EXPECTED
1
1.6259
1.62590000000000000000000000000000000001
2
.60989
.9916201510000000000000000000000000000026
3
.83859
.8315627424270900000000000000000000000085
fiddle
One option is to use a recursive CTE; it, though, expects that sample data can be sorted, somehow, so I added the ID column which starts with 1, while other values are incremented by 1:
Sample data:
SQL> with
2 test (id, col) as
3 (select 1, 1.62590 from dual union all
4 select 2, 0.60989 from dual union all
5 select 3, 0.83859 from dual
6 ),
Query begins here:
7 product (id, col, prod) as
8 (select id, col, col
9 from test
10 where id = 1
11 union all
12 select t.id, t.col, t.col * p.prod
13 from test t join product p on p.id + 1 = t.id
14 )
15 select id,
16 round(prod, 10) result
17 from product;
ID RESULT
---------- ----------
1 1,6259
2 ,991620151
3 ,831562742
SQL>
You can use a MODEL clause:
SELECT *
FROM (SELECT ROW_NUMBER() OVER (ORDER BY id) AS rn, result FROM table_name)
MODEL
DIMENSION BY (rn)
MEASURES ( result, 0 AS expected)
RULES (
expected[rn] = result[cv()] * COALESCE(expected[cv()-1], 1)
)
order by rn;
Which, for the sample data:
CREATE TABLE table_name (id, Result) AS
SELECT 1, 1.62590 FROM DUAL UNION ALL
SELECT 2, 0.60989 FROM DUAL UNION ALL
SELECT 3, 0.83859 FROM DUAL;
Outputs:
RN
RESULT
EXPECTED
1
1.6259
1.6259
2
.60989
.991620151
3
.83859
.83156274242709
fiddle
I am trying to use a query to return the count from rows such that the date of the rows matches the maximum date for that column in the table.
Oracle SQL: version 11.2:
The following syntax would seem to be correct (to me), and it compiles and runs. However, instead of returning JUST the count for the maximum, it returns several counts more or less like the "HAIVNG" clause wasn't there.
Select ourDate, Count(1) as OUR_COUNT
from schema1.table1
group by ourDate
HAVING ourDate = max(ourDate) ;
How can this be fixed, please?
You can use:
SELECT MAX(ourDate) AS ourDate,
COUNT(*) KEEP (DENSE_RANK LAST ORDER BY ourDate) AS ourCount
FROM schema1.table1
or:
SELECT ourDate,
COUNT(*) AS our_count
FROM (
SELECT ourDate,
RANK() OVER (ORDER BY ourDate DESC) AS rnk
FROM schema1.table1
)
WHERE rnk = 1
GROUP BY ourDate
Which, for the sample data:
CREATE TABLE table1 (ourDate) AS
SELECT SYSDATE FROM DUAL CONNECT BY LEVEL <= 5 UNION ALL
SELECT SYSDATE - 1 FROM DUAL;
Both output:
OURDATE
OUR_COUNT
2022-06-28 13:35:01
5
db<>fiddle here
I don't know if I understand what you want. Try this:
Select x.ourDate, Count(1) as OUR_COUNT
from schema1.table1 x
where x.ourDate = (select max(y.ourDate) from schema1.table1 y)
group by x.ourDate
One option is to use a subquery which fetches maximum date:
select ourdate, count(*)
from table1
where ourdate = (select max(ourdate)
from table1)
group by ourdate;
Or, a more modern approach (if your database version supports it; 11g doesn't, though):
select ourdate, count(*)
from table1
group by ourdate
order by ourdate desc
fetch first 1 rows only;
You can use this SQL query:
select MAX(ourDate),COUNT(1) as OUR_COUNT
from schema1.table1
where ourDate = (select MAX(ourDate) from schema1.table1)
group by ourDate;
This question already has answers here:
LISTAGG in Oracle to return distinct values
(24 answers)
Closed 2 years ago.
I am trying to retrieve multiple concatenated distinct varchars (named CODE in query) from multiple rows on multiple columns using LISTAGG in oracle 12C, LISTAGG(distinct...) solves the problem on 19c but I must work with 12c.
Unexpected result
I get the above result using this query:
SELECT
T.c1 A,
T.c2 B,
LISTAGG( TI.CODE , ';' ) WITHIN GROUP (ORDER BY TI.CODE) AS COLUMNX1,
LISTAGG( TE.CODE, ' ;') WITHIN GROUP (ORDER BY TE.CODE ) AS COLUMNX2,
LISTAGG(TR.CODE, '; ') WITHIN GROUP (ORDER BY TR.CODE ) AS COLUMNX3
FROM TABLE1 T
INNER join TABLE_I TI on TI.fk_c2 = T.c2
INNER join TABLE_E TE on TE.fk_c2 = T.c2
INNER join TABLE_R TR on TR.fk_c2 = T.c2
WHERE T.d = *parameter*
GROUP BY
T.c1,
T.c2;
I want to retrieve this :
Expected result
The yellow marked strings should not be retrieved.
In evey line of the query result, the columns COLUMNX1, COLUMNX2, COLUMNX3 have the same number of concatenated strings, that's why I have the duplication problem.
furthermore, TABLE_I, TABLE_E and TABLE_R all have a foreign key fk_c2 that references TABLE1.c2
EDIT:
I added a with Clause to retrieve distinct values first then I joined it to my select statement
Expected result is retrieved with this query
WITH TEMP AS (
SELECT fk_c2, LISTAGG(code, ',') WITHIN GROUP (ORDER BY code) AS X1
FROM (
SELECT DISTINCT *
FROM TABLE_I
GROUP BY fk_c2 ) COLUMNX1
INNER JOIN
(SELECT fk_c2, LISTAGG(code, ',') WITHIN GROUP (ORDER BY code) AS X2
FROM (
SELECT DISTINCT *
FROM TABLE_E)
GROUP BY fk_c2 ) COLUMNX2
ON COLUMNX1.fk_c2 = COLUMNX2.fk_c2
INNER JOIN
(SELECT fk_c2, LISTAGG(code, ',') WITHIN GROUP (ORDER BY code) AS X3
FROM(
SELECT DISTINCT *
FROM TABLE_R)
GROUP BY fk_c2 ) COLUMNX3
ON COLUMNX1.fk_c2 = COLUMNX3.fk_c2
)
SELECT
T.c1 A,
T.c2 B,
tmp.X1,
tmp.X2,
tmp.X3
FROM TABLE1 T
INNER join temp tmp on tmp.fk_c2 = T.c2
WHERE T.d = *parameter*
GROUP BY
T.c1,
T.c2
tmp.X1,
tmp.X2,
tmp.X3;
You'll need additional step: first find distinct values, then aggregate them. For example:
SQL> with test (id, col) as
2 (select 1, 'x' from dual union all
3 select 1, 'x' from dual union all
4 --
5 select 2, 'w' from dual union all
6 select 2, 't' from dual union all
7 select 2, 'w' from dual union all
8 --
9 select 3, 'i' from dual
10 ),
11 -- first find distinct values ...
12 temp as
13 (select distinct id, col from test)
14 -- ... then aggregate them
15 select id,
16 listagg(col, ';') within group (order by col) result
17 from temp
18 group by id;
ID RESULT
---------- ----------
1 x
2 t;w
3 i
SQL>
This question already has answers here:
How to use Oracle ORDER BY and ROWNUM correctly?
(5 answers)
Closed 4 years ago.
I have two tables X and Y.
when I run below query for table X
select * from
( select rownum as rn, A.* from X as A order by A.IDdesc) where rn between 0
and 1000000;
I get result as
rn Id name
1 1 xxx
2 2 yyy
3 4 zzz
but for Y table when same query is executed I get result as
select * from
( select rownum as rn, A.* from Y as A order by A.IDdesc) where rn between 0
and 1000000;
rn Id name
5 1 xxx
7 2 yyy
10 4 zzz
rn in Y table is getting some random numbers. Not able to understand this behavior. ny help would be appreciated.
The ROWNUM pseudo-column is added to the selected columns in the order Oracle retrieves the rows and then the ORDER BY clause is applied. What you appear to want is to order the rows first and then generate the ROWNUM against this ordering but that is not what your query will do.
For table X, it happens that Oracle retrieves the rows in the same order as the id column. However, for table Y, the rows are not retrieved in the same order as the id column so the ROWNUM is in the order the rows were retrieved and then a different ordering is applied so the ROWNUM values appear shuffled.
What you should do is to apply the ORDER BY before generating the ROWNUM pseudo-column so they are in-sync:
SELECT *
FROM (
SELECT rownum as rn,
A.*
FROM (
SELECT *
FROM X
ORDER BY ID desc
) A
)
WHERE rn BETWEEN 0 AND 1000000;
In my database I have a table with column that indicates the code of each record ( aside from ID column ). this field is unique and each time the user tries to insert a record into the table, the first unused code should be assigned to the record. Now the table has the column of codes with the following order :
+------+
code
+------+
1
+------+
2
+------+
3
+------+
5
+------+
I want a query to return 4 as the result.
Note that this query is highly frequent in my system and the best query with minimum execution time will be appreciated.
Is using a self-join acceptable? If so:
-- your test data:
WITH data AS (SELECT 1 AS code FROM DUAL
UNION SELECT 2 FROM DUAL
UNION SELECT 3 FROM DUAL
UNION SELECT 5 FROM DUAL)
-- request:
SELECT COALESCE(MIN(d1.code+1),1)
FROM data d1 LEFT JOIN data d2 ON d1.code+1 = d2.code
WHERE d2.code IS NULL;
This will build the list of data.code without a successor. And using MIN(...+1) you will get the first empty slot. I used COALESCE(...) in order to handle the specific case where there isn't any entry in the data table.
And alternate form using a sequence generator might lead to better performances as is does not require the whole table to be traversed in order to perform the aggregate function MIN():
-- your test data:
WITH data AS (SELECT 1 AS code FROM DUAL
UNION SELECT 5 FROM DUAL
UNION SELECT 2 FROM DUAL
UNION SELECT 3 FROM DUAL)
-- request:
SELECT T.code FROM (SELECT d1.code
FROM (SELECT LEVEL code FROM DUAL CONNECT BY LEVEL < 9999) d1 LEFT JOIN data d2
ON d1.code = d2.code
WHERE d2.code IS NULL
ORDER BY d1.code ASC
) T WHERE ROWNUM < 2
The drawback is you now have an upper limit hard-coded. It might be dynamically inferred from the data table though. So is is not really blocking. I let you compare timings yourself.
this field is unique and each time the user tries to insert a record into the table, the first unused code should be assigned to the record
Please note however this will lead to a race condition if two concurrent sessions try to insert a row at the same time. Given your example, they will both try to insert a row with code = 4 -- obviously both will not succeed in doing so as your column is unique...
I recently use the code below:
SELECT t1.id+1
FROM table t1
LEFT OUTER JOIN table t2 ON (t1.id + 1 = t2.id)
WHERE t2.id IS NULL
/* and rownum = 1 Need to use a sub select if you want this to work */
ORDER BY t1.id;
I run it every time that I need to insert a new row and use the minimum unused id.
I hope it works for your purposes.
select level unusedval from dual connect by level < 10
minus
select tno from t2);
you can change level condition dependents on max value.