Oracle: Overwrite values in a column with the longest string - sql

I’m running into a problem.
Say, I have columns called “C1, C2, C3....” in a table. I’d like to use the longest string in C1 to replace every other cells in C1 column without disturbing other columns.
I tired several ways but I cannot get my Oracle code run. Could someone please show me a sample code to do this problem? I typed my question using a cellphone so I apologize for not showing you my code. But I think my description is fine... Thank you!

I would use window functions. Oracle has a very convenient functionality with keep:
select max(col1) keep (dense_rank first order by len(col1) desc) over () as col1,
col2, col3, . . .
from t;
You can incorporate this into an update:
update t
set col1 = (select select max(col1) keep (dense_rank first order by len(col1) desc) over () as col1
from t
);

For example:
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
SQL> update test set
2 dname = (select max(dname) --> MAX fixes TOO-MANY-ROWS because ACCOUNTING
3 from test -- and OPERATIONS have same length
4 where length(dname) = (select max(length(dname))
5 from test
6 )
7 );
4 rows updated.
SQL> select * from test;
DEPTNO DNAME LOC
---------- -------------- -------------
10 OPERATIONS NEW YORK
20 OPERATIONS DALLAS
30 OPERATIONS CHICAGO
40 OPERATIONS BOSTON
SQL>
[EDIT, GROUP BY]
Another example is based on a different table, which reflects what you described in a comment. The DEPTNO (department number) is used to "group" employees, and I'm going to update the JOB column value to the longest job name within that department.
Query is similar to the previous one; it just joins appropriate columns (DEPTNO) throughout code.
Sample data:
SQL> select * from test order by deptno, ename;
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK MANAGER
KING PRESIDENT --> the longest in DEPTNO = 10
MILLER CLERK
20 ADAMS CLERK
FORD ANALYST
JONES MANAGER --> as long as ANALYST, but MAX(JOB) will return this value
SCOTT ANALYST
SMITH CLERK
30 ALLEN SALESMAN --> the longest in DEPTNO = 30
BLAKE MANAGER
JAMES CLERK
MARTIN SALESMAN
TURNER SALESMAN
WARD SALESMAN
Update and the result:
SQL> update test t set
2 t.job = (select max(t1.job)
3 from test t1
4 where t1.deptno = t.deptno
5 and length(t1.job) = (select max(length(t2.job))
6 from test t2
7 where t2.deptno = t1.deptno
8 )
9 );
14 rows updated.
SQL> select * from test order by deptno, ename;
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK PRESIDENT
KING PRESIDENT
MILLER PRESIDENT
20 ADAMS MANAGER
FORD MANAGER
JONES MANAGER
SCOTT MANAGER
SMITH MANAGER
30 ALLEN SALESMAN
BLAKE SALESMAN
JAMES SALESMAN
MARTIN SALESMAN
TURNER SALESMAN
WARD SALESMAN

Related

What is the best way(in case of performance) to find out the user details with maximum salary?

We have user details with a column of salary also, how can we print the user details with the maximum salary, I don't want to use the Subquery, and yeah how subquery will reduce the performance.
I know this query is wrong but I want something like this:
select User_name, user_id
from dual where salary=Max(salary);
Analytic functions help.
Using a CTE (which is kind of a subquery; don't be afraid of it, it doesn't bite and won't affect performance), query might look like this (based on sample Scott's schema):
SQL> select ename, sal from emp order by sal desc;
ENAME SAL
---------- ----------
KING 5000 --> this is the highest salary
FORD 3000 --> FORD and SCOTT share the 2nd place
SCOTT 3000
JONES 2975
BLAKE 2850
CLARK 2450
ALLEN 1600
TURNER 1500
MILLER 1300
WARD 1250 --> WARD and MARTIN are then 9th
MARTIN 1250
ADAMS 1100
JAMES 950
SMITH 800
14 rows selected.
Query is then
SQL> with temp as
2 (select ename,
3 dense_rank() over (order by sal desc) rnk
4 from emp
5 )
6 select ename
7 from temp
8 where rnk = 1;
ENAME
----------
KING
SQL>
Why dense_rank? Because two (or more) employees can have the same salary so they "rank" the same. For example, if you want to know whose salary is ranked as 9th, you'd
SQL> l8
8* where rnk = 1
SQL> c/1/9
8* where rnk = 9
SQL> /
ENAME
----------
WARD
MARTIN
SQL>
Query you suggested (although wrong, but - I got the idea) looks like this:
SQL> select ename
2 from emp
3 where sal = (select max(sal) from emp);
ENAME
----------
KING
SQL>
And yes, it affects performance because you're fetching data from the same emp table twice: once to find the max salary (in a subquery), and then in the main query to find who it belongs to.

Ignore column in the WHERE clause if the parameter is null, else use IN clause to filter the column in WHERE clause

I need to write a query where I should Ignore any filter on that column if the respective parameter is Null, but should filter with IN clause if the said parameter is not null. I am trying to use the below query but I am not able to make it work. It is the HR DB and Employees table in Oracle 11 XE and I am trying to pass Job ID as a param and this param could be null or it could contain multiple values.
What I have done so far -
SELECT * FROM HR.EMPLOYEES
WHERE
CASE WHEN NVL(:PARAM_JOB_ID,'NONE')= 'NONE' THEN 'NONE' ELSE JOB_ID END IN NVL(:PARAM_JOB_ID,'NONE');
Please guide.
I would use IS NULL logic here:
SELECT *
FROM HR.EMPLOYEES
WHERE JOB_ID IN (:PARAM_JOB_ID) OR :PARAM_JOB_ID IS NULL;
You'll have to split values in :PARAM_JOB_ID into rows. Something like this (Scott's sample schema and its EMP table):
select job, ename
from emp
where ( job in (select trim(regexp_substr(:param_job_id, '[^,]+', 1, level))
from dual
connect by level <= regexp_count(:param_job_id, ',') + 1
)
or :param_job_id is null
)
order by job, ename;
Demonstration in SQL*Plus:
SQL> select job, ename
2 from emp
3 where ( job in (select trim(regexp_substr('&&param_job_id', '[^,]+', 1, level))
4 from dual
5 connect by level <= regexp_count('&&param_job_id', ',') + 1
6 )
7 or '&&param_job_id' is null
8 )
9 order by job, ename;
Enter value for param_job_id: --> empty parameter returns all rows
JOB ENAME
--------- ----------
ANALYST FORD
ANALYST SCOTT
CLERK ADAMS
CLERK JAMES
CLERK MILLER
CLERK SMITH
MANAGER BLAKE
MANAGER CLARK
MANAGER JONES
PRESIDENT KING
SALESMAN ALLEN
SALESMAN MARTIN
SALESMAN TURNER
SALESMAN WARD
14 rows selected.
SQL> undefine param_job_id
SQL> /
Enter value for param_job_id: CLERK, PRESIDENT
JOB ENAME
--------- ----------
CLERK ADAMS
CLERK JAMES
CLERK MILLER
CLERK SMITH
PRESIDENT KING
SQL>

bind parameter in oracle EBS

i need to add list of values to a bin parameter on report builder in oracle e-business suite
but in this list of values i need the first option is all and other values are result of select statement like the following:
all
10
20
30
....
so if the user clicked on "all" the report will query all departments
if the user clicked on any other specific department, the report will query this specific department
how can i add this "all" option??
I don't use EBS, but I do know Reports and some SQL so - here's my suggestion.
Adding the "all" option is simple - union it with other values. Something like this:
SQL> select value
2 from (select 1 rn, 'all' value from dual
3 union all
4 select 2 rn, to_char(deptno) from dept
5 )
6 order by rn, value;
VALUE
----------------------------------------
all
10
20
30
40
SQL>
Then, in a query, you'd use it as
select e.deptno, e.ename, e.job
from emp e
where e.deptno = case when :par_deptno = 'all' then to_char(e.deptno)
else :par_deptno
end
order by e.deptno, e.ename;
The above example, ran in SQL*Plus (so don't mind a substitution instead of a bind variable):
First, I'm passing 10:
SQL> select e.deptno, e.ename, e.job
2 from emp e
3 where e.deptno = case when '&&par_deptno' = 'all' then to_char(e.deptno)
4 else '&&par_deptno'
5 end
6 order by e.deptno, e.ename;
Enter value for par_deptno: 10
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK MANAGER
10 KING PRESIDENT
10 MILLER CLERK
Now, let's try all:
SQL> undefine par_deptno
SQL> /
Enter value for par_deptno: all
DEPTNO ENAME JOB
---------- ---------- ---------
10 CLARK MANAGER
10 KING PRESIDENT
10 MILLER CLERK
20 ADAMS CLERK
20 FORD ANALYST
20 JONES MANAGER
20 SCOTT ANALYST
20 SMITH CLERK
30 ALLEN SALESMAN
30 BLAKE MANAGER
30 JAMES CLERK
30 MARTIN SALESMAN
30 TURNER SALESMAN
30 WARD SALESMAN
14 rows selected.
SQL>
Looks OK to me. Now, how will it look like in EBS, I have no idea.

Oracle- sql query to print odd number of rows when we do not have number data type columns

I was trying to print odd numbers of rows from my table without taking taking help of my numeric cloumns
when I try to execute this query I was getting only first row.
select * from emp3 where mod(rownum,2)=1;
emp3 is my table name.
and when I use my one of the numeric columns in place of rownum I was getting desired output.
select * from emp3 where mod(eid,2)=1 order by eid;
where eid is a numeric column in the table.
But what if do not have a numeric column and I want to print only odd number of rows from the table?
Help me!
Try to execute the below query
select * from (select rownum rn ,column from column_name) where mod(rn,2) <> 0
and please refer to this link for better understanding the concept of rownum https://www.youtube.com/watch?v=QMyw1jumGyQ
If the EID column isn't numeric, then use something that is. For example, ROW_NUMBER gives such an information:
SQL> with temp as
2 (select empno, ename, job sal,
3 row_number() over (order by null) rn
4 from emp
5 )
6 select *
7 from temp
8 where mod(rn, 2) = 1;
EMPNO ENAME SAL RN
---------- ---------- --------- ----------
7369 SMITH CLERK 1
7521 WARD SALESMAN 3
7654 MARTIN SALESMAN 5
7782 CLARK MANAGER 7
7839 KING PRESIDENT 9
7876 ADAMS CLERK 11
7902 FORD ANALYST 13
7 rows selected.
SQL>
Or even ROWNUM you already tried to use:
SQL> with temp as
2 (select empno, ename, job sal,
3 rownum rn
4 from emp
5 )
6 select *
7 from temp
8 where mod(rn, 2) = 1;
EMPNO ENAME SAL RN
---------- ---------- --------- ----------
7369 SMITH CLERK 1
7521 WARD SALESMAN 3
7654 MARTIN SALESMAN 5
7782 CLARK MANAGER 7
7839 KING PRESIDENT 9
7876 ADAMS CLERK 11
7902 FORD ANALYST 13
7 rows selected.
SQL>

Deleting duplicate records with ROWNUM?

I know how to delete duplicate records with ROWID.
Please guide me to delete duplicate records with ROWNUM in Oracle.
That just won't work. From documentation:
For each row returned by a query, the ROWNUM pseudocolumn returns a number indicating the order in which Oracle selects the row from a table or set of joined rows. The first row selected has a ROWNUM of 1, the second has 2, and so on.
Its value is set at the moment you run the query and can be changed, depending on how you fetch data (different ORDER BY will produce different ROWNUM value for the same row). As it is sequential, you can't set "groups" of ROWNUM values (for example, so that it goes from 1, 2, 3 for one set, then 1, 2, 3, 4, 5 for another - you'll always get 1, 2, 3, 4, 5, 6, 7, 8).
If you planned to do something like this:
SQL> create table test as
2 select e.empno, e.deptno, d.dname, e.ename
3 from emp e join dept d on e.deptno = d.deptno;
Table created.
SQL> select * from test order by deptno;
EMPNO DEPTNO DNAME ENAME
---------- ---------- -------------- ----------
7782 10 ACCOUNTING CLARK
7839 10 ACCOUNTING KING
7934 10 ACCOUNTING MILLER
7369 20 RESEARCH SMITH
7902 20 RESEARCH FORD
7566 20 RESEARCH JONES
7900 30 SALES JAMES
7844 30 SALES TURNER
7654 30 SALES MARTIN
7521 30 SALES WARD
7499 30 SALES ALLEN
7698 30 SALES BLAKE
12 rows selected.
SQL> delete from test t
2 where t.empno in (select a.empno
3 from (select t1.empno, t1.deptno, t1.dname, rownum rn
4 from test t1
5 ) a
6 where a.rn > 1
7 );
11 rows deleted.
As you can see, all rows (but one) are duplicates. Here's why:
SQL> rollback;
Rollback complete.
SQL> select a.deptno, a.empno, a.rn, a.rn1
2 from (select t1.empno, t1.deptno, t1.dname, rownum rn,
3 row_number() over (partition by t1.deptno order by null) rn1
4 from test t1
5 ) a;
DEPTNO EMPNO RN RN1
---------- ---------- ---------- ----------
10 7782 2 1
10 7839 1 2
10 7934 3 3
20 7369 5 1
20 7902 4 2
20 7566 6 3
30 7900 7 1
30 7844 8 2
30 7654 9 3
30 7521 10 4
30 7499 11 5
30 7698 12 6
12 rows selected.
See? RN (ROWNUM) has all values from 1, 2, ..., 12. RN1 (ROW_NUMBER, which allows us to set partitions) does the job correctly. So, if you used RN1 instead of RN, it would work:
SQL> delete from test t
2 where t.empno in (select a.empno
3 from (select t1.empno, t1.deptno, t1.dname, rownum rn,
4 row_number() over (partition by t1.deptno order by null) rn1
5 from test t1
6 ) a
7 where a.rn1 > 1
8 );
9 rows deleted.
SQL> select * From test;
EMPNO DEPTNO DNAME ENAME
---------- ---------- -------------- ----------
7782 10 ACCOUNTING CLARK
7369 20 RESEARCH SMITH
7900 30 SALES JAMES
SQL>
[EDIT: deleting duplicates #2]
Here's another example which shows how/what to do if you want to delete duplicates. It is based on the "ROWID technique" (although there are another ones too).
Back to the table we've been working with. Suppose that we want to keep only one distinct job per department:
SQL> select deptno, job, dname, empno, ename
2 from test
3 order by deptno, job;
DEPTNO JOB DNAME EMPNO ENAME
---------- --------- -------------- ---------- ----------
10 CLERK ACCOUNTING 7934 MILLER
10 MANAGER ACCOUNTING 7782 CLARK
10 PRESIDENT ACCOUNTING 7839 KING
20 ANALYST RESEARCH 7902 FORD
20 CLERK RESEARCH 7369 SMITH
20 MANAGER RESEARCH 7566 JONES
30 CLERK SALES 7900 JAMES
30 MANAGER SALES 7698 BLAKE
30 SALESMAN SALES 7844 TURNER -- leave
30 SALESMAN SALES 7654 MARTIN -- only
30 SALESMAN SALES 7521 WARD -- one
30 SALESMAN SALES 7499 ALLEN -- salesman
12 rows selected.
in department 10, there are no duplicates - 3 employees, each of them doing their own job
the same goes for department 20
however, in department 30, there are 4 SALESMEN and we want to keep only one - another ones are duplicates
It means that you have to take both columns - DEPTNO and JOB - into account when deleting rows. Let's do that:
SQL> delete from test a
2 where rowid > (select min(rowid)
3 from test b
4 where a.deptno = b.deptno --> take both DEPTNO ...
5 and a.job = b.job --> and JOB into account
6 );
3 rows deleted.
The result: departments 10 and 20 didn't change, but in department 30 now we have only one salesman, just as we wanted:
SQL> select deptno, job, dname, empno, ename
2 from test
3 order by deptno, job;
DEPTNO JOB DNAME EMPNO ENAME
---------- --------- -------------- ---------- ----------
10 CLERK ACCOUNTING 7934 MILLER
10 MANAGER ACCOUNTING 7782 CLARK
10 PRESIDENT ACCOUNTING 7839 KING
20 ANALYST RESEARCH 7902 FORD
20 CLERK RESEARCH 7369 SMITH
20 MANAGER RESEARCH 7566 JONES
30 CLERK SALES 7900 JAMES
30 MANAGER SALES 7698 BLAKE
30 SALESMAN SALES 7844 TURNER
9 rows selected.
SQL>