Can we specify no of cycles in sequences in oracle? - sql

I started to create a sequence in Oracle. While going through the oracle documentation I got this prototype
Create Sequence SeqTest5
Start With 0
Increment by 1
Min value 0
Maxvalue 8
NoCycle --I got to know we can give this as 'Cycle' which will again
-- Repeat the loop. But my doubt is why cannot we specify number of
-- Loops. Such as Cycle 20
NoCache --I got to know we can give certain buffer lenght via cache
Can you Please explain me why cannot we declare it as I have tried it and got this error
1 create sequence seqtest4
2 cache 30,
3* cycle 20,
SQL> /
cache 30,
*
ERROR at line 2:
ORA-00933: SQL command not properly ended
For Example:-
TNUM
0
1
4
2
3
5
6
7
8
This 0-8 should write 10 times and stop.

You can't specify the number of cycles; just whether or not you want to cycle. The CREATE SEQUENCE syntax is here.
There are a few problems with your CREATE SEQUENCE above:
The commas - they don't belong; just get rid of them.
Specifying CYCLE 20 - you can specify CYCLE or NOCYCLE only. The default is NOCYCLE.
If you specify CYCLE you must also specify a MAXVALUE.
Addendum: Question updated with actual requirement, which is to count 1-8 ten times. Here's how to do it without sequences; it's based on an often-used Oracle trick for generating number sequences:
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <= 8
The statement above will output the numbers 1 through 8, in order. To repeat it ten times you need to do another "1 through 10" counter, then cross join it to the "1 through 8", then make sure it orders correctly. This complicates thing a bit, which can be seen in the final answer:
SELECT SeqCounter FROM (
SELECT SeqCounter, CycleCounter FROM (
SELECT LEVEL AS SeqCounter FROM DUAL CONNECT BY LEVEL <= 8)
CROSS JOIN (
SELECT LEVEL AS CycleCounter FROM DUAL CONNECT BY LEVEL <= 10)
) ORDER BY CycleCounter, SeqCounter
The statement above will give the output requested in the question.

Wouldn't this be best handled with a modulo function?
CREATE SEQUENCE seqtest5 START WITH 0 INCREMENT BY 1 MINVALUE 0 MAXVALUE 80 NOCYCLE;
SELECT mod(seqtest5.nextval, 9) from dual;
0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5, 6, ...
ORA-08004: sequence SEQTEST5.NEXTVAL exceeds MAXVALUE and cannot be instantiated

Related

Sequence id is not properly inserted

I have created a sequence but its not inserting ids in sequence order.
For Ex:
First I have created one set of record seq number generated as 1, 2, 3, 4
Again I have created another set of records seq started from 8, 9, 10
For 3rd time I have created another set of records seq id got generated as 5, 6, 7
(which is not correct, I want the seq id to be continued as 11, 12, 13)
So 5, 6, 7 is wrong, I need 11, 12, 13 to be generated
What's wrong in my below sequence create query?
CREATE SEQUENCE "LEASE_REPAYMENT_SEQ"
MINVALUE 1 MAXVALUE 9999999999999999999999999999 INCREMENT BY 1
START WITH 146724 CACHE 20 NOORDER NOCYCLE NOKEEP NOSCALE GLOBAL ;
If you check the sequence definition, you'll see that you define it as NOORDER.
The Oracle Documentation says
Specify NOORDER if you do not want to guarantee sequence numbers are generated in order of request. This is the default.
So what you see is an expected bahaviour and I assume your database is a RAC instance (as this effect can be observed on RAC only).
Having said that, there are good reasons to allow this small dis-order of the assigned IDs (which is caused by the caching as each RAC instance gets it own cache size to work with).
The positive side of this apprach is that there is no need to synchronize the sequence between the instances - a task that could produce a big overhead.

How can I read the first n rows of table a based upon the number of rows in table b?

I have a table "L20" that contains 1 to 20 values "HDIF" in it, sorted in ascending order. I need to extract the first 1 to 10 of those values into table "T10" depending upon the number of values in table "L20". I'm using Windows 10, Libreoffice 6.4.4, with Firebird 3 database. I've tried the CASE statement and the DECODE statement on the COUNT of rows in "L20", but neither seems to work.
If I put in a numeral for the SELECT on table "L20" then it works correctly. Anyone have an idea of how to solve? The purpose of this query is to calculate a golf handicap which uses [up to] the best (lowest) 10 scores of [up to] the last (most recent) 20 games played. Here is the coding:
/* Qry_Index_Calc - calculates handicap index from top 10 differentials of last 20 games */
/* Source is "VW_Plyr_Diff" which has handicap differentials already calculated. */
SELECT (AVG ("T10"."HDIF") * .96) "Index", (Count ("T10"."HDIF")) FROM
/* Get only the games needed if less than 20 games have been played. */
(
SELECT FIRST
DECODE ((SELECT COUNT (*) FROM "L20"),
1, 1
, 2, 1
, 3, 1
, 4, 1
, 5, 1
, 6, 1
, 7, 2
, 8, 2
, 9, 3
, 10, 3
, 11, 4
, 12, 4
, 13, 5
, 14, 5
, 15, 6
, 16, 6
, 17, 7
, 18, 8
, 19, 9
, 10)
"L20"."HDIF"
FROM
/* Get up to 20 of the most recent (last) games played. */
( SELECT FIRST 20 "PlayerID" "PID", "GID" "GID",
RANK ( ) OVER ( PARTITION BY "PlayerID" ORDER BY "Diff" ) "Rnk",
"Diff" "HDIF", "Date" "Gdate"
FROM "Vw_Plyr_Diff"
WHERE "PlayerID" = 1)
"L20"
) "T10"
You need to put parentheses around the expression in FIRST. As specified in the Firebird 3.0 Language Reference for FIRST, SKIP:
SELECT
[FIRST <m>] [SKIP <n>]
FROM ...
...
<m>, <n> ::=
<integer-literal>
| <query-parameter>
| (<integer-expression>)
So, use
select first (decode(...)) ....
When using subqueries directly in first, you need to use double parentheses (once for the expression, and once for the fact that sub-queries in expressions are enclosed in parentheses.
The SQL standard OFFSET/FETCH clauses introduced in Firebird 3 do not support expressions.
Beware, your current code doesn't specify an ORDER BY, this means it is undefined exactly which rows are returned, it will depend on location of data inside the database, the access plan, etc. I would recommend that you add an appropriate ORDER BY clause to ensure the returned rows are as expected.
It looks like you're trying to SELECT from the derived table L20 defined in the FROM clause, and not from an actual table L20. If you want to be able to do that, then L20 most be specified as a common table expression.

how connect by works to generate numbers

For the documentation, I know connect by can be used together with prior, in hierarchical queries. But quite often I see it is used to generate numbers:
SQL> select level from dual connect by level < 10;
LEVEL
----------
1
2
3
4
5
6
7
8
9
9 rows selected
SQL>
How it works here ? I mean how it generate 1, then 2, and so on. I can not see a hierarchy here, and connect by is not being used with prior. This has confused me for a long time.
The query does a linear recursive call.
Level is fake column generated by the recursion which tells the recursion depth of current iteration. The connect by clause does not need to refer to prior, it is condition just like any other which tells 'If this row has level smaller than 10, union it to the result set'

Oracle SQL connect by level

Can anyone explain the behavior of the below query:-
select level,t.*
from
( select 'one','two'from dual
union all
select 'one','two'from dual
) t
connect by level<=2
There are 2 rows in the inner query. I was expecting 4 rows of output, but i get 6 rows of output. Why is it so and how does this work?
The query starts with one of your two rows and adds both rows, then it continues with the second row and adds both rows again.
Change your query like this:
select level,t.*
from
( select 'one' from dual
union all
select 'two' from dual
) t
connect by level<=2;
This makes it easier to see what happens:
1 one
2 one
2 two
1 two
2 one
2 two
Read this http://docs.oracle.com/cd/B19306_01/server.102/b14200/queries003.htm
When level <= 1, you will get each of the records 1 time.
When level <= 2, then you will get each level 1 time (for level 1) + the number of records in the table
(That means for this condition 2 records having level 1 + 2*2 records having level 2. This is the reason you are getting 6 records.)
CONNECT BY LEVEL gives following number of rows
x+x2+x3+x4+...x^n = Sx^n
where n is number of LEVEL and x is number of rows in a table

Access ancestors

I have an Access db table, that holds couples of values: (SourceId, DestinationId). Both values are taken from the same list of Id's.
I want to create a list (query result?) of all item's ancestors. Ie, if the user enters Id=15, I'd like to return all Id's that are destinations for source-15, but also their destinations etc.
For example, if my table hold
15, 3 |
15, 4 |
4, 7 |
4, 8 |
3, 5 |
5, 2 |
1, 9
Id like to return 3, 4, 7, 8, 5, 2 (but not return 9).
I guess the solution should include some VBA code with loops or recursion, but I got confused by recordsets versus collections.
Any idea?
Thanks,
Aviram
Unfortunately Access SQL lacks the CONNECT BY syntax that Oracle uses to do hierarchical queries. However, if you are prepared to create a temporary table you can emulate it in Access with a loop.
In this example your original table is "LinkTab" and the temporary table will be "TmpTree" an you are starting from SourceID 15.
First execute:
SELECT SourceID, DestID, 1 as Lvl INTO TmpTree FROM LinkTab WHERE SourceID = 15
Then in a loop, repeatedly execute:
INSERT INTO TmpTree ( SourceID, DestID, Lvl )
SELECT newrows.SourceID, newrows.DestID, TmpTree.Lvl + 1
FROM TmpTree INNER JOIN LinkTab newrows ON TmpTree.DestID = newrows.SourceID
WHERE TmpTree.Lvl = (SELECT MAX(Lvl) FROM TmpTree)
until the statement returns zero affected rows (or if you can't detect this, count the rows in TmpTree each time and stop when they don't increase)
Now your results can be retrieved with :
SELECT DestID FROM TmpTree
And finally, to tidy up:
DROP TABLE TmpTree
I've tested these statements in the Access Query designer and they get the desired result.