Oracle sqlplus functions shows as ### - sql

After submitting a select query, which contains functions such as row_number() or any other function the result is ####. If I use rownum as something, it shows ### if I use just rownum everything is ok.
I had this problem with other generic columns but I could simply use column columnname format 9999;
The problem is not that there is not enough space, there is only one digit per record.
I have googled all over the internet and nothing has answered my problem yet.
Does anyone know what could be the problem with functions and how to format them?
select ROW_NUMBER() OVER (ORDER BY student_surname) "Nr.",
student_surname || ' ' || student_name "Student",
NVL(sum(m.stipend),0) + NVL(sum(m.compensation),0) "Total"
from student s
inner join money m on m.student_id=s.id_student
group by student_surname, student_name;
Have tried clear columns, did not work.

It looks as if you formatted numeric column with a wrong format, which doesn't allow all digits to be displayed.
For example, this is someone's salary - looks OK:
SQL> select sal from emp where rownum = 1;
SAL
----------
920
But, if you formatted it as follows (i.e. saying that I want to have only two digits (99) for that column), the result is ###:
SQL> col sal format 99
SQL> select sal from emp where rownum = 1;
SAL
---
###
SQL>
What to do? The simplest way is to clear formatting:
SQL> col sal clear
SQL> select sal from emp where rownum = 1;
SAL
----------
920
SQL>
Another possibility is that numformat (in general) is wrongly set; all these columns are NUMBER, and all of them are affected with this set numformat:
SQL> set numformat 9
SQL> select empno, mgr, sal, deptno from emp where rownum = 1;
EMPNO MGR SAL DEPTNO
---------- ---------- ---------- ----------
########## ########## ########## ##########
How to fix that? Exit SQL*Plus and reconnect.

Related

Trouble when joining two queries Oracle SQL

I have a table on employees like this:
ENAME JOB
Jack Clerk
Adam Manager
Raphael President
And my idea is to get the names that have the maximum length and the minimum length (1 per each) and in case the length is the same, take the one that goes first alphabetically (for example in the case of Jack and Adam, both with 4 characters, it would take Adam):
ENAME LENGTH
Adam 4
Raphael 7
I couldn't find the way of doing it in one unique query so I tried to join two queries but it keeps giving me error ('ORA-00933: SQL command not properly ended') and I don't know why:
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MAX(LENGTH(ENAME)) FROM emp)
ORDER BY ENAME
FETCH FIRST 1 ROW ONLY
union all
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MIN(LENGTH(ENAME)) FROM emp)
ORDER BY ENAME
FETCH FIRST 1 ROW ONLY;
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MAX(LENGTH(ENAME)) FROM emp)
--ORDER BY 1
--FETCH FIRST 1 ROW ONLY
union
SELECT ENAME, LENGTH(ENAME) FROM EMP
GROUP BY ENAME
HAVING LENGTH(ENAME) = (SELECT MIN(LENGTH(ENAME)) FROM emp)
ORDER BY 1
FETCH FIRST 1 ROW ONLY;
One method uses aggregation and union all:
select min(name) keep (dense_rank first order by len(name) asc), min(len(name))
from emp
union all
select min(name) keep (dense_rank first order by len(name) desc, max(len(name))
from emp;
The keep syntax is Oracle's rather verbose way of having a "first" aggregation function.

ORACLE SQL retrieve n rows without subqueries or derived tables

I'm doing my SQL exercises but I got stuck in one. I need to retrieve the employees with the two highest salaries, but I can't use any type of subquery or derived table. I do it with a subquery like this:
SELECT *
FROM (SELECT * FROM emp ORDER BY sal DESC) new_emp
WHERE ROWNUM < 3;
I also know that this can be achieved using the WITH clause, but I'm wondering if there is any alternative to this.
PS: I'm using Oracle 11.
If you are Oracle version 12.1 or above you can use a row limiting clause. In your case you would just use the subquery plus the row limiting clause like so:
SELECT * FROM emp
ORDER BY sal DESC
FETCH FIRST 5 ROWS ONLY;
Source: https://oracle-base.com/articles/12c/row-limiting-clause-for-top-n-queries-12cr1#top-n
This is actually a pathetic method, in my opinion, but you can use a join:
select e.col1, e.col2, . . .
from emp e left join
emp e2
on e2.salary >= e.salary
group by e.col1, e.col2, . . .
having count(distinct e2.salary) <= 2;
Note: this is really equivalent to a dense_rank(), so if there are ties, you'll get more than two rows. It is easy enough to fix this (assuming you have a unique identifier for each row), but the fix complicates the logic and hides the basic idea.
A good exercise should help to prepare to solve practical problems. So the important thing in this one is not the usage of subquery but to realize that the two highes salaries can have hunderts of employees.
While using the #MT0 view workaround this is the query
CREATE VIEW sal_ordered_emps AS
SELECT e.*,
row_number() over (order by sal desc) as RN
FROM SCOTT.emp e
ORDER BY sal DESC;
select e.* from scott.emp e join
sal_ordered_emps soe on e.sal = soe.sal and rn <= 2
;
result as explained can be more than 2 records
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- ------------------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 19.04.1987 00:00:00 3000 20
7839 KING PRESIDENT 17.11.1981 00:00:00 5000 10
7902 FORD ANALYST 7566 03.12.1981 00:00:00 3000 20
This is cheating but... instead of using a subquery you can define a view:
CREATE VIEW sal_ordered_emps AS
SELECT *
FROM emp
ORDER BY sal DESC;
Then you can do:
SELECT * FROM sal_ordered_emps WHERE ROWNUM < 3;
Alternatively, you can do it with a pipelined function...
CREATE OR REPLACE PACKAGE emp_pkg
AS
TYPE emp_table IS TABLE OF EMP%ROWTYPE;
FUNCTION get_max_sals(
n INT
) RETURN emp_table PIPELINED;
END;
/
CREATE OR REPLACE PACKAGE BODY emp_pkg
AS
FUNCTION get_max_sals(
n INT
) RETURN emp_table PIPELINED
AS
cur SYS_REFCURSOR;
in_rec EMP%ROWTYPE;
i INT := 0;
BEGIN
OPEN cur FOR SELECT * FROM EMP ORDER BY SAL DESC;
LOOP
i := i + 1;
FETCH cur INTO in_rec;
EXIT WHEN cur%NOTFOUND OR i > n;
PIPE ROW(in_rec);
END LOOP;
CLOSE cur;
RETURN;
END;
END;
/
SELECT *
FROM TABLE( emp_pkg.get_max_sals( 2 ) );
This solution use no subquery, but requires three steps:
-- Q1
select max(sal) from scott.emp;
-- Q2
select max(sal) from scott.emp where sal < {result of Q1};
select * from scott.emp where sal in ({result of Q1},{result of Q2});
General you'll need N+1 queries to get top-N salaries emps.

Display the name of the maximum salary holder (WITHOUT USING A SUBQUERY)

Say there's a table
Name Salary
Joe 4000
Steve 6000
I could just do this
select name from emp where salary = (select max(salary) from emp);
but is there a way to do this without using a subquery?? Please help.
EDIT: Sorry I forgot to mention that I'm using Oracle 10g and LIMIT doesn't work on it
You didn't mention the version of Oracle.
On Oracle 12 there is a new low limiting clause that can be used:
SELECT name
FROM emp
ORDER BY salary desc
FETCH FIRST 1 ROWS ONLY;
There are examples in documentation: https://docs.oracle.com/database/121/SQLRF/statements_10002.htm#BABEAACC
On earlier versions it can't be done without using a subquery, but if you must then create a view:
CREATE VIEW emp_ordered AS
SELECT *
FROM emp
ORDER BY salary desc;
and then query this view in this way:
SELECT * FROM emp_ordered
WHERE rownum <=1
ANSI SQL answer (no dbms specified):
select Name, Salary
from emp
order by Salary desc
fetch first 1 row only
Edit: Will work with newer Oracle versions.
In Oracle 12c, the top-n row limiting feature is introduced. Which allows to ORDER the rows without an additional subquery. So, no more dependency on ROWNUM and explicit sorting in a subquery.
For example,
SQL> SELECT ename, sal FROM emp ORDER BY sal DESC
2 FETCH FIRST 1 row only;
ENAME SAL
---------- ----------
KING 5000
SQL>
Update Regarding duplicate rows
There is an option WITH TIES which will include the duplicate rows.
For example,
SQL> insert into emp(empno, ename, sal) values(1234, 'LALIT', 5000);
1 row created.
SQL> SELECT ename, sal FROM emp ORDER BY sal DESC FETCH FIRST 1 ROWS WITH TIES;
ENAME SAL
---------- ----------
KING 5000
LALIT 5000
SQL>
Try this
SELECT name FROM emp
ORDER BY salary DESC
LIMIT 1
Try
select * from emp order by salary DESC limit 1

Displaying names using conditions [duplicate]

This question already has answers here:
Fetch the rows which have the Max value for a column for each distinct value of another column
(35 answers)
Closed 8 years ago.
I would like to know if I have a certain table, let's say table X
which contains salary and names, how would I display the maximum salary along with corresponding names?
Thank you.
select salary, name
from X
where salary = (select MAX(salary) from X)
Let's see this using EMP table example :
SQL> WITH DATA AS(
2 SELECT MAX(sal) max_sal FROM emp)
3 SELECT ename, sal
4 FROM emp
5 WHERE sal = (SELECT max_sal FROM DATA)
6 /
ENAME SAL
---------- ----------
KING 5000
SQL>

inserting in table before declaring cursor

Can I use the insert statement with values coming from a select statement on another table in EXECUTE IMMEDIATE?
Like :
execute immediate('insert into table values(select rowid from table where column='NEW')');
if there is no possibility of this can I put an insert statement before the declaration of a cursor in a procedure.
thanks a lot.
Yes you can but you'd need to sort out your syntax and quotes:
execute immediate('insert into table (column_name) select rowid from table where column=''NEW''');
EDIT:
Better still, use a bind variable instead of the hard coded reference to the column name.
What results did you get when you tested it?
Your syntax is a little off, but, as you can see below, it's definitely doable.
SQL> CREATE TABLE emp2 AS SELECT * FROM emp WHERE 1 = 0;
Table created.
SQL> BEGIN
2 EXECUTE IMMEDIATE 'INSERT INTO emp2 (empno, ename, job) SELECT e.empno, e.ename, e.job FROM emp e WHERE e.deptno = 10';
3 END;
4 /
PL/SQL procedure successfully completed.
SQL> SELECT * FROM emp2;
EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------------------- ---------- ---------- ----------
7782 CLARK MANAGER
7839 KING PRESIDENT
7934 MILLER CLERK
SQL>