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'
Related
I came across a query to create a dummy table like this
CREATE TABLE destination AS
SELECT level AS id,
CASE
WHEN MOD(level, 2) = 0 THEN 10
ELSE 20
END AS status,
'Description of level ' || level AS description
FROM dual
CONNECT BY level <= 10;
SELECT * FROM destination;
1 20 Description of level 1
2 10 Description of level 2
3 20 Description of level 3
4 10 Description of level 4
5 20 Description of level 5
6 10 Description of level 6
7 20 Description of level 7
8 10 Description of level 8
9 20 Description of level 9
10 10 Description of level 10
10 rows selected.
Could you share some insights of how this works ? First, the missing of PRIOR is unbeknownst to me. Second, I don't get how the tree is constructed. From the level it looks like they are all branched out from the same root.
This gimmick was noticed by a DB professional, Mikito Harakiri, and shared on AskTom. It has been adopted in the Oracle community, although it is undocumented (it actually goes against the documentation), and its use is somewhat dangerous in that Oracle may at some point make it no longer work. (Although with its already massive use, it would be insane for Oracle to take it back.)
The rows are indeed branching from the same root, the single row of dual. You can use any other table that has EXACTLY ONE row for the same trick. If you start with two rows (or you use the trick on your own table, with many rows), you will quickly run into trouble. There are ways around that, you will pick that up over time. You may be interested in following the Oracle forum, at OTN, people use this trick all the time there.
Here is an article that discusses this trick: http://www.sqlsnippets.com/en/topic-11821.html
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
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
Trying to interpret this query...
SELECT blah1, blah2, ... FROM (SELECT level-1 HOUR_ID
FROM dual
CONNECT BY level <= 24
) LU_HOUR
what does blah values contain? what does level mean to a dual table?
dual is a dummy table with one column (named dummy) and one row (containing X for the dummy column).
CONNECT BY level <= 24 is a hierarchical query term which means that for each match at some level you connect each possible match at the next level provided that your condition is true. Here, LEVEL is automatically incremented, and you can refer to the parent match with PRIOR.
This is a trick to forge a query result with 24 rows, from 0 to 23.
This:
select *
from dual
connect by level <= i
...will return result as
1
2
3
...
i
Can the query be modified to get result row wise? i.e
1 2 3 .....i
The functionality you're after is called "pivot"--it's converting row data into columnar data. The opposite is called "unpivot". There is PIVOT/UNPIVOT syntax, but it isn't available until Oracle 11g.
On Oracle 9i+, CASE statements are used while prior to that you need to use DECODE to construct the logic so the values come out in columns. Here's an example for addressing if the limit to LEVEL is five on Oracle 9i+:
SELECT MAX(CASE WHEN LEVEL = 1 THEN LEVEL END) AS one,
MAX(CASE WHEN LEVEL = 2 THEN LEVEL END) AS two,
MAX(CASE WHEN LEVEL = 3 THEN LEVEL END) AS three,
MAX(CASE WHEN LEVEL = 4 THEN LEVEL END) AS four,
MAX(CASE WHEN LEVEL = 5 THEN LEVEL END) AS five
FROM DUAL
CONNECT BY LEVEL <= 5
The aggregate function MAX is necessary to "flatten" the resultset into a single row/record.
If you got this far, you're thinking "but I don't want to have to specify for every column--I want it to be dynamic based on i...". There's two issues:
There is a limit to the number of columns - see ORA-01792 maximum number of columns in a table or view is 1000. That goes for 8i & 9i, anyways. And frankly, needing to generate that many columns raises serious questions about what you're trying to do with the resultset, if there might be a better approach...
Dynamic requirements means using dynamic SQL
Try this:
select trim(both ',' from sys_connect_by_path(level, ',')) as string
from dual
where level = 100
connect by level <= 100
update: Testing the output:
SQL>
SQL> select trim(both ',' from sys_connect_by_path(level, ',')) as string
2 from dual
3 where level = 20
4 connect by level <= 20
5 /
STRING
--------------------------------------------------------------------------------
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
another update: Guess I haven't read all comments well enough before posting, sorry. :) If you need to select each number as a separate column, then yes, see, OMG Ponies' answer - it's either pivot or dynamic SQL. :)