Different result for to_number in Order By clause in Oracle - sql

I have two queries which give error ORA-01722: invalid number when trying to convert CHAR to NUMBER.
SELECT to_number('NYC TERM') FROM dual;
WITH
x AS (SELECT 'NYC TERM' AS col FROM dual
UNION
SELECT '33' FROM dual)
SELECT *
FROM X
ORDER BY to_number(col);
If I remove the second SELECT in UNION query works fine. Why is it behaving different?
The issue is when I run a query as a whole returning other rows it gives error, but when I run for just that particular record which has this kind of data it acts fine.
WITH
x AS (SELECT 'NYC TERM' AS col FROM dual)
SELECT * FROM X ORDER BY to_number(col);

This is a bit long for a comment.
I think what is happening is that Oracle is short-circuiting the order by for performance reasons. With only one row, there is no need to sort at all, so even the key doesn't get evaluated. This is perhaps more clearly seen in this absurd example:
WITH x AS (SELECT 'NYT TERM' AS col FROM DUAL)
SELECT * FROM X ORDER BY length(col) / 0;
This returns one row with one column, 'NYT TERM'. No error.
I suppose this is considered a "feature".

Related

ORDER BY and UNION in SQLPLUS issue

I am giving the following error: "ORA-01785: ORDER BY item must be the number of a SELECT-list expression" when I try to select id_prof using "order by" while making a union between to columns from different tables.
The command is as follows:
select substr(nume, 1, 1)||'.'||regexp_replace(prenume, '[aeiou]', null, 1, 0, 'i') as "Rododendron"
from studenti
union
select ceil(sqrt(to_number(substr (id_prof, 2, 1))*2)) as "Fata de con"
from profesori
where grup_didactic = 'Lect'
order by to_number(substr (id_prof, 2, 1)) desc;
The tables are in the following pictures: FirstPicture SecondPicture
I would like to have in the end two columns.
The first one should include the first letter from "nume", concatenated with '.' and "prenume" without vowels (column named "Rododendron").
In the second one I want to have the square root, rounded upper, from the double of id_prof's number (column named "Fata de con"), for everything that can be found in "profesori", where grup_didactic = 'lector' and everything is ordered desc after id_prof.
Any help, please?
Oracle says that you can't sort the result by column that isn't contained in the SELECT column list; such as in this simple Scott's schema example:
SQL> select ename from emp
2 union
3 select dname from dept
4 order by substr(ename, 1, 3);
order by substr(ename, 1, 3)
*
ERROR at line 4:
ORA-01785: ORDER BY item must be the number of a SELECT-list expression
I'd say that sorting is the least of your problems, currently. UNION won't return two columns; remove ORDER BY and see for yourself - if you're lucky, you'll get a single column.
This is what you do now:
select col from studenti
union
select another_col from profesori
while you want to get
select col, another_col
from ...
FROM clause is tricky, as it seems that you're selecting from two different tables. Can you join them so that query looks like the second option? If not, you can always do a Cartesian product, but that will most probably be a wrong result.
It would help if you provided sample input data and explain how to get the result out of that input.

Trying to generate Fibonacci series using recursive WITH clause, getting error: 'cycle detected while executing'

I am trying to generate Fibonacci series using below query (recursive WITH clause).
WITH X(Pnbr,Cnbr) AS
(SELECT 0, 1 FROM dual
UNION ALL
SELECT X.Cnbr, X.Pnbr+X.Cnbr FROM X
WHERE X.Cnbr<50
)
SELECT * FROM X
But I am getting this error
ORA-32044: cycle detected while executing recursive WITH query
Why?
Your data at first iteration would be
PNBR CNBR
0 , 1
1 , 1 + 0
So, CNBR is 1 is first two rows.. A Cycle is detected!
The CONNECTING condition has to be unique!
So probably you would need to maintain an iterator.
ROWNUM is what I used here for it.
WITH X(iter,Pnbr,Cnbr) AS
(SELECT 1,0, 1 FROM dual
UNION ALL
SELECT iter + rownum, X.Cnbr, X.Pnbr+X.Cnbr FROM X
WHERE iter < 50
)
SELECT iter,Pnbr FROM X;
DEMO
I agree with the diagnosis in M. Ravisankar's Answer (from 2015), but not with the remedy.
To handle precisely the situation presented in the original post, recursive CTE offers the CYCLE clause. In this problem, while there will be repeated values in the Pnbr column as well as in the Cnbr column, when considered separately, there are no repeated values (duplicates) in the composite (Pnbr, Cnbr).
So, the query can be written like this:
WITH X(Pnbr,Cnbr) AS
(SELECT 0, 1 FROM dual
UNION ALL
SELECT X.Cnbr, X.Pnbr+X.Cnbr FROM X
WHERE X.Cnbr<50
)
cycle Pnbr, Cnbr set cycle to 'Y' default 'N' ----
SELECT Pnbr, Cnbr FROM X
Notice the cycle clause (second to last line), and also SELECT Pnbr, Cnbr as opposed to SELECT * (if we selected * here, we would also get the cycle column, which we don't need).
modify the column in the where clause. Use X.Pnbr+X.Cnbr instead of X.Cnbr as the condition so that Oracle uses the two referenced columns for the row cycling detection.
WITH X(Pnbr,Cnbr) AS
(SELECT 0, 1 FROM dual
UNION ALL
SELECT X.Cnbr, X.Pnbr+X.Cnbr FROM X
-- Cnbr column is used to detect the cycle data
WHERE X.Pnbr+X.Cnbr < 50
)
SELECT * FROM X;
According to the Oracle Doc:
If you omit the CYCLE clause, then the recursive WITH clause returns an error if cycles are discovered. In this case, a row forms a cycle if one of its ancestor rows has the same values for all the columns in the column alias list for query_name that are referenced in the WHERE clause of the recursive member.
Query Outputs:

SQLite: UNION of n places ORDER BY size together with all the capitals?

I try to select from ne_10m_populated_places both the 15 biggest cities together with the 3~5 ones where FEATURECLA='Admin-0 capital' (the countries capitals). So for my area, I should get back ~18-20 places. I'am very beginner to SQL, and don't know where how basic operators chain up. I tried:
SELECT * FROM ne_10m_populated_places ORDER BY POP_MAX DESC LIMIT '15'
OR WHERE FEATURECLA='Admin-0 capital'
The first line works, but it fails when I add it the second line. Help welcome !
EDIT: no working answer yet.
The ordering of your statements is incorrect and you need to do a UNION if you want to add specific results.
In this example, we find the 15 most populated cities and then UNION specific cities that you've specified.
In the first query of the UNION, it is turned into a sub-select since ORDER BY will affect the entire UNION otherwise.
SELECT *
FROM (
SELECT *
FROM ne_10m_populated_places
ORDER BY POP_MAX DESC
LIMIT 15
)
UNION
SELECT *
FROM ne_10m_populated_places
WHERE FEATURECLA = 'Admin-0 capital'

PostgreSQL nested CTE and UNION

I'm trying to learn SQL, using PostgreSQL 9.1.3. I would like to understand some behavior that strikes me as inconsistent. To wit:
This works:
WITH innermost AS (SELECT 2)
SELECT * FROM innermost
UNION SELECT 3;
I get this:
?column?
----------
2
3
This works:
WITH outmost AS (
(WITH innermost AS (SELECT 2)
SELECT * FROM innermost)
)
SELECT * FROM outmost;
Result:
?column?
----------
2
This also works:
WITH outmost AS (
SELECT 1
UNION (WITH innermost AS (SELECT 2)
SELECT * FROM innermost)
)
SELECT * FROM outmost;
I get this:
?column?
----------
1
2
But this does not work:
WITH outmost AS (
SELECT 1
UNION (WITH innermost as (SELECT 2)
SELECT * FROM innermost
UNION SELECT 3)
)
SELECT * FROM outmost;
Result:
ERROR: relation "innermost" does not exist
LINE 4: SELECT * FROM innermost
To my way of thinking, either the last one should succeed or one of the other ones should fail. I don't see the pattern. Is there some general rule that would enable me to predict what combinations of nested CTEs and UNIONs will or will not work?
The mystery is solved: the behavior I was observing is a known bug. I sent the same original post to a PostgreSQL-specific list and got this answer:
This is a bug :-(. The parse analysis code seems to think that WITH
can only be attached to the top level or a leaf-level SELECT within a
set operation tree; but the grammar follows the SQL standard which
says no such thing. The WITH gets accepted, and attached to the
intermediate-level UNION which is where syntactically it should go,
and then it's entirely ignored during parse analysis. Will see about
fixing it.
regards, tom lane
http://archives.postgresql.org/pgsql-novice/2012-07/msg00113.php

Purposely having a query return blank entries at regular intervals

I want to write a query that returns 3 results followed by blank results followed by the next 3 results, and so on. So if my database had this data:
CREATE TABLE table (a integer, b integer, c integer, d integer);
INSERT INTO table (a,b,c,d)
VALUES (1,2,3,4),
(5,6,7,8),
(9,10,11,12),
(13,14,15,16),
(17,18,19,20),
(21,22,23,24),
(25,26,37,28);
I would want my query to return this
1,2,3,4
5,6,7,8
9,10,11,12
, , ,
13,14,15,16
17,18,19,20
21,22,23,24
, , ,
25,26,27,28
I need this to work for arbitrarily many entries that I select for, have three be grouped together like this.
I'm running postgresql 8.3
This should work flawlessly in PostgreSQL 8.3
SELECT a, b, c, d
FROM (
SELECT rn, 0 AS rk, (x[rn]).*
FROM (
SELECT x, generate_series(1, array_upper(x, 1)) AS rn
FROM (SELECT ARRAY(SELECT tbl FROM tbl) AS x) x
) y
UNION ALL
SELECT generate_series(3, (SELECT count(*) FROM tbl), 3), 1, (NULL::tbl).*
ORDER BY rn, rk
) z
Major points
Works for a query that selects all columns of tbl.
Works for any table.
For selecting arbitrary columns you have to substitute (NULL::tbl).* with a matching number of NULL columns in the second query.
Assuming that NULL values are ok for "blank" rows.
If not, you'll have to cast your columns to text in the first and substitute '' for NULL in the second SELECT.
Query will be slow with very big tables.
If I had to do it, I would write a plpgsql function that loops through the results and inserts the blank rows. But you mentioned you had no direct access to the db ...
In short, no, there's not an easy way to do this, and generally, you shouldn't try. The database is concerned with what your data actually is, not how it's going to be displayed. It's not an appropriate scope of responsibility to expect your database to return "dummy" or "extra" data so that some down-stream process produces a desired output. The generating script needs to do that.
As you can't change your down-stream process, you could (read that with a significant degree of skepticism and disdain) add things like this:
Select Top 3
a, b, c, d
From
table
Union Select Top 1
'', '', '', ''
From
table
Union Select Top 3 Skip 3
a, b, c, d
From
table
Please, don't actually try do that.
You can do it (at least on DB2 - there doesn't appear to be equivalent functionality for your version of PostgreSQL).
No looping needed, although there is a bit of trickery involved...
Please note that though this works, it's really best to change your display code.
Statement requires CTEs (although that can be re-written to use other table references), and OLAP functions (I guess you could re-write it to count() previous rows in a subquery, but...).
WITH dataList (rowNum, dataColumn) as (SELECT CAST(CAST(:interval as REAL) /
(:interval - 1) * ROW_NUMBER() OVER(ORDER BY dataColumn) as INTEGER),
dataColumn
FROM dataTable),
blankIncluder(rowNum, dataColumn) as (SELECT rowNum, dataColumn
FROM dataList
UNION ALL
SELECT rowNum - 1, :blankDataColumn
FROM dataList
WHERE MOD(rowNum - 1, :interval) = 0
AND rowNum > :interval)
SELECT *
FROM dataList
ORDER BY rowNum
This will generate a list of those elements from the datatable, with a 'blank' line every interval lines, as ordered by the initial query. The result set only has 'blank' lines between existing lines - there are no 'blank' lines on the ends.