with clause logic [message #649724] |
Mon, 04 April 2016 15:59 |
sivaparam
Messages: 16 Registered: March 2005
|
Junior Member |
|
|
Hi there,
Could you please explain the logic of this sql?
WITH n( n ) AS
(
SELECT 1 FROM dual
UNION ALL
SELECT n+1 FROM n WHERE n<=9999
)
SELECT * FROM n;
|
|
|
Re: with clause logic [message #649727 is a reply to message #649724] |
Mon, 04 April 2016 18:21 |
|
Barbara Boehmer
Messages: 9088 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
This is row number generation using recursive subquery factoring. It generates the values 1 through 10,000 with one value per row. The letter n has been used as both a subquery alias and a column alias. I will try to explain it one piece at a time, using a smaller simpler example that generates the numbers 1 through 3 using n as a column alias and t as a subquery alias.
-- The following selects individual numbers, one per row, one row per query:
SCOTT@orcl> SELECT 1 n FROM dual t;
N
----------
1
1 row selected.
SCOTT@orcl> SELECT 2 n FROM dual t;
N
----------
2
1 row selected.
SCOTT@orcl> SELECT 3 n FROM dual t;
N
----------
3
1 row selected.
-- The following selects the same 3 numbers but uses UNION ALL to join the results:
SCOTT@orcl> SELECT 1 n FROM dual t
2 UNION ALL
3 SELECT 2 n FROM dual t
4 UNION ALL
5 SELECT 3 n FROM dual t;
N
----------
1
2
3
3 rows selected.
The following uses the above query as a sub-query and selects from it:
SCOTT@orcl> SELECT *
2 FROM (SELECT 1 n FROM dual
3 UNION ALL
4 SELECT 2 n FROM dual
5 UNION ALL
6 SELECT 3 n FROM dual) t;
N
----------
1
2
3
3 rows selected.
The following uses a WITH clause, also known as a sub-query factoring clause.
It is like declaring a subquery before the query instead of within it.
It produces the same result as the query above.
SCOTT@orcl> WITH t(n) AS
2 (SELECT 1 FROM dual
3 UNION ALL
4 SELECT 2 FROM dual
5 UNION ALL
6 SELECT 3 FROM dual)
7 SELECT * FROM t;
N
----------
1
2
3
3 rows selected.
The following uses the recursive subquery factoring feature of the subquery factoring clause
by using "SELECT n+1 FROM t WHERE n<=2) to select from itself multiple times,
adding one to the previous value of n each time until it reaches 2+1, which is 3,
producing the same results as the query above.
SCOTT@orcl> WITH t(n) AS
2 (SELECT 1 FROM dual
3 UNION ALL
4 SELECT n+1 FROM t WHERE n<=2)
5 SELECT * FROM t;
N
----------
1
2
3
3 rows selected.
The following substitutes 9 for 2, producing 10 rows. If you use 9999 instead it would produce 10,000 rows, so you can see where it would save a lot of lines of code, instead of doing 10,000 queries with union all between each.
SCOTT@orcl> WITH t(n) AS
2 (SELECT 1 FROM dual
3 UNION ALL
4 SELECT n+1 FROM t WHERE n<=9)
5 SELECT * FROM t;
N
----------
1
2
3
4
5
6
7
8
9
10
10 rows selected.
Row number generation is commonly used for various things and this is one of various methods. Recursive subquery factoring also has other usages besides row number generation.
[Updated on: Tue, 05 April 2016 01:01] Report message to a moderator
|
|
|
|
|
|
|
|
|
Re: with clause logic [message #650358 is a reply to message #650357] |
Sat, 23 April 2016 05:55 |
|
live4learn
Messages: 41 Registered: September 2013 Location: Bangalore, India
|
Member |
|
|
My Bad . I was trying with to_date and to_char both .
SQL> with t(n) as
2 (
3 select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual
4 UNION ALL
5 SELECT TO_DATE(N,'DD-MON-YYYY')+1 FROM T WHERE N<=TO_DATE('20-MAR-2016','DD-MON-YYYY')
6 )
7 select * from t
8 /
with t(n) as
(
select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual
UNION ALL
SELECT TO_DATE(N,'DD-MON-YYYY')+1 FROM T WHERE N<=TO_DATE('20-MAR-2016','DD-MON-YYYY')
)
select * from t
ORA-01790: expression must have same datatype as corresponding expression
SQL> select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual;
TO_DATE('1-MAR-2016','DD-MON-Y
------------------------------
3/1/2016
SQL> select TO_DATE('1-MAR-2016','DD-MON-YYYY')+1 from dual;
TO_DATE('1-MAR-2016','DD-MON-Y
------------------------------
3/2/2016
SQL>
|
|
|
|
Re: with clause logic [message #650360 is a reply to message #650359] |
Sat, 23 April 2016 06:01 |
Bill B
Messages: 1971 Registered: December 2004
|
Senior Member |
|
|
And it can cause an error depending on the default nls setting. Since a to_date on a date does an implicit conversation to string before it converts back to a date
|
|
|
|
|
|
Re: with clause logic [message #650371 is a reply to message #650370] |
Sat, 23 April 2016 13:19 |
|
live4learn
Messages: 41 Registered: September 2013 Location: Bangalore, India
|
Member |
|
|
still giving the same error to me:
NLS_RDBMS_VERSION 11.2.0.1.0
SQL> with t(n) as
2 (
3 select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual
4 UNION ALL
5 SELECT n+1 FROM t WHERE n<=TO_DATE('20-MAR-2016','DD-MON-YYYY')
6 )
7 select * from t
8 /
with t(n) as
(
select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual
UNION ALL
SELECT n+1 FROM t WHERE n<=TO_DATE('20-MAR-2016','DD-MON-YYYY')
)
select * from t
ORA-01790: expression must have same datatype as corresponding expression
SQL> SELECT * FROM NLS_DATABASE_PARAMETERS where parameter ='NLS_DATE_FORMAT';
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_DATE_FORMAT DD-MON-RR
SQL>
[Updated on: Sat, 23 April 2016 13:28] Report message to a moderator
|
|
|
|
Re: with clause logic [message #650373 is a reply to message #650372] |
Sat, 23 April 2016 13:41 |
|
live4learn
Messages: 41 Registered: September 2013 Location: Bangalore, India
|
Member |
|
|
SQL> select banner from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for 32-bit Windows: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 - Production
SQL>
I tried altering session parameter for nls_date_formate:
SQL> alter session set NLS_DATE_FORMAT='DD-MON-YYYY';
Session altered
SQL>
SQL> with t(n) as
2 (
3 select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual
4 UNION ALL
5 SELECT n+1 FROM t WHERE n <= TO_DATE('20-MAR-2016','DD-MON-YYYY')
6 )
7 select * from t
8 /
with t(n) as
(
select TO_DATE('1-MAR-2016','DD-MON-YYYY') from dual
UNION ALL
SELECT n+1 FROM t WHERE n <= TO_DATE('20-MAR-2016','DD-MON-YYYY')
)
select * from t
ORA-01790: expression must have same datatype as corresponding expression
SQL>
[Updated on: Sat, 23 April 2016 13:45] Report message to a moderator
|
|
|
Re: with clause logic [message #650374 is a reply to message #650373] |
Sat, 23 April 2016 13:45 |
Bill B
Messages: 1971 Registered: December 2004
|
Senior Member |
|
|
That's why. The version of with you are using isn't available until Oracle 12. Not a problem though. You can do the exact same result using a row generator
|
|
|
|
Re: with clause logic [message #650376 is a reply to message #650375] |
Sat, 23 April 2016 13:51 |
|
Barbara Boehmer
Messages: 9088 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
Yes, recursive subquery factoring was available in 11.2.
http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10002.htm#BCEJGIBG
So, the version isn't the problem.
live4learn,
Are you running it from SQL*Plus or from something else?
If not running the code from SQL*Plus, then please try it from SQL*Plus. If you are running the code from SQL*Plus, then please post the results of:
show spparameter compatible
Also, please post the results of:
SELECT name, value, description FROM v$parameter WHERE name = 'compatible';
[Updated on: Sat, 23 April 2016 14:04] Report message to a moderator
|
|
|
Re: with clause logic [message #650377 is a reply to message #650376] |
Sat, 23 April 2016 14:09 |
Bill B
Messages: 1971 Registered: December 2004
|
Senior Member |
|
|
I stand corrected. I was under the impression that it was an Oracle 12c feature. Oh will isn't the first or last time I was wrong.
|
|
|
Re: with clause logic [message #650378 is a reply to message #650376] |
Sat, 23 April 2016 14:14 |
|
live4learn
Messages: 41 Registered: September 2013 Location: Bangalore, India
|
Member |
|
|
Running from sql*plus . working fine with numbers.
SQL> show parameters compatible;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
compatible string 11.2.0.0.0
SQL> with t(n) as (
2 select 2 from dual
3 union all
4 select n+1 from t where n <=5)
5 select * from t;
N
----------
2
3
4
5
6
SQL>
SQL> SELECT name, value, description FROM v$parameter WHERE name = 'compatible';
NAME VALUE DESCRIPTION
-------------------------------------------------------------------------------- -------------------------------------------------------------------------------- --------------------------------------------------------------------------------
compatible 11.2.0.0.0 Database will be completely compatible with this software version
SQL>
SQL> SELECT * FROM NLS_SESSION_PARAMETERS;
PARAMETER VALUE
------------------------------ ----------------------------------------
NLS_LANGUAGE AMERICAN
NLS_TERRITORY AMERICA
NLS_CURRENCY $
NLS_ISO_CURRENCY AMERICA
NLS_NUMERIC_CHARACTERS .,
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD-MON-YYYY
NLS_DATE_LANGUAGE AMERICAN
NLS_SORT BINARY
NLS_TIME_FORMAT HH.MI.SSXFF AM
NLS_TIMESTAMP_FORMAT DD-MON-RR HH.MI.SSXFF AM
NLS_TIME_TZ_FORMAT HH.MI.SSXFF AM TZR
NLS_TIMESTAMP_TZ_FORMAT DD-MON-RR HH.MI.SSXFF AM TZR
NLS_DUAL_CURRENCY $
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE
17 rows selected
SQL>
[Updated on: Sat, 23 April 2016 14:21] Report message to a moderator
|
|
|
|
|
|
|
|
Re: with clause logic [message #650384 is a reply to message #650383] |
Sat, 23 April 2016 14:53 |
|
Barbara Boehmer
Messages: 9088 Registered: November 2002 Location: California, USA
|
Senior Member |
|
|
At least that's progress. Try also casting the date in the where clause.
WITH t(n) AS
(SELECT CAST (TO_DATE ('1-MAR-2016', 'DD-MON-YYYY') AS DATE) n FROM dual
UNION ALL
SELECT CAST (n+1 AS DATE) FROM t WHERE n <= CAST (TO_DATE ('20-MAR-2016', 'DD-MON-YYYY') AS DATE))
SELECT * FROM t;
[Updated on: Sat, 23 April 2016 15:03] Report message to a moderator
|
|
|
|
|
|
|
Re: with clause logic [message #650390 is a reply to message #650389] |
Sat, 23 April 2016 21:45 |
Solomon Yakobson
Messages: 3273 Registered: January 2010 Location: Connecticut, USA
|
Senior Member |
|
|
Still, I'd try
WITH t(n) AS
(SELECT CAST (TO_DATE ('1-MAR-2016', 'DD-MON-YYYY') AS DATE) n FROM dual
UNION ALL
SELECT CAST (n+1 AS DATE) FROM t WHERE n <= TO_DATE ('20-MAR-2016', 'DD-MON-YYYY'))
SEARCH DEPTH FIRST BY n SET ord_n
SELECT * FROM t
ORDER BY ord_n;
SY.
[Updated on: Sat, 23 April 2016 21:46] Report message to a moderator
|
|
|
Re: with clause logic [message #650406 is a reply to message #650390] |
Sun, 24 April 2016 06:55 |
Bill B
Messages: 1971 Registered: December 2004
|
Senior Member |
|
|
One thing your site should look into is have your dba install the latest patch set on your database. This would fix a lot of problems. I'm not saying patch to fix your casting problem. I'm saying patch because your site should be up to date.
|
|
|