Remove MISS from username in Oracle - oracle

I have a query in which I want to remove the MISS, MR type of things from the user_name
I tried with below query
SELECT 0 user_id, '--- Select ---' user_name
FROM DUAL
UNION
SELECT DISTINCT user_id, LTRIM (user_name) user_name
FROM xxcus.xxacl_pn_user_det_v
ORDER BY user_name
but still it is not working for me.
Here is the screenshot

If you have several possible prefixes you want to delete, you can use regexp_replace():
regexp_replace(user_name, '^(MISS|MS\.|MS|MRS\.|MRS|MR\.|MR)\s*', '') as user_name
^ anchors the search at the beginning of the string, (...|...|...) means match any of the choices in parentheses, and \s is a single space; \s* means zero or more consecutive spaces. All that is deleted from the beginning of each string. The dot . must be escaped with backspace (otherwise it stands for "any single character").
If you need case-insensitive matching, if you may also have Miss in addition to MISS, use the full syntax of regexp_replace.
Edit: one more thing... the alternatives are tried one by one, from left to right, and the first match is used. So MS\. should appear before MS, otherwise MS (without a dot) will match MS in MS. SMITH and this will leave the dot and the space at the beginning of the string. I had to correct that in the solution.

You can use REPLACE() function like
REPLACE(user_name,'MISS','') as user_name

if you have column struct like (mr|mrs|other)/space/username you can try this
with users(user_name) as
(select 'mr user name1' from dual union all
select 'miss username2 ' from dual union all
select 'other username 3' from dual )
select substr(user_name,instr(user_name,' ')+1) real_username from users
output
REAL_USERNAME
----------------
user name1
username2
username 3
it substr from first founded space symbol
in your query
SELECT 0 user_id, '--- Select ---' user_name
FROM DUAL
UNION
SELECT DISTINCT user_id, substr(user_name,instr(user_name,' ')+1) user_name
FROM xxcus.xxacl_pn_user_det_v
ORDER BY user_name
if you want --- Select--- start from top you can:
select user_id, user_name
from (
SELECT 0 user_id, '--- Select ---' user_name, 1 order_by
FROM DUAL
UNION
SELECT DISTINCT user_id, substr(user_name,instr(user_name,' ')+1) user_name, 2 order_by
FROM xxcus.xxacl_pn_user_det_v
)
ORDER BY order_by, user_name

Related

Oracle- calculating difference between two time when value of another fields is changed

I need to calculation time when another field change in oracle.
For instance, I have table which has 3 fields. Username, Date, and Status, all of them are varchar. Status has two values 0,1. Now, if for one user changing status happen i need to calculate time beteween them. in fact i want to calculate between when status='0' to become 1. For example, user a in 20170101 has status=0 until 20170105, the difference date between them is 3, also from 20170107 has status='0' again until 20170110, the difference is 2. so 2+3=5
username status date
a 0 20170101
a 1 20170105
a 0 20170107
a 1 20170110
username status day
a 0 5
You may be looking for something like this. However, there are many assumptions here - see my Comments under your original post. In the solution below, I kept the "-1" from your weird date arithmetic. I also ignore status 0 if it is not followed by status 1. And if consecutive rows with the same status are possible, I only take CONSECUTIVE rows with status changing from 0 to 1. This may not be the correct handling if such situations are possible.
with
inputs ( username, status, dt ) as (
select 'a', '0', '20170101' from dual union all
select 'a', '1', '20170105' from dual union all
select 'a', '0', '20170107' from dual union all
select 'a', '1', '20170110' from dual
)
-- End of SIMULATED inputs (for testing only, not part of the solution).
-- SQL query begins BELOW THIS LINE. Use your actual table and column names.
select username,
sum(diff) as days_in_status_0
from (
select username,
case when status = '1'
and lag(status) over (partition by username order by dt) = '0'
then to_date(dt, 'yyyymmdd') -
to_date(lag(dt) over(partition by username order by dt), 'yyyymmdd')
- 1
end as diff
from inputs
)
group by username
;
USERNAME DAYS_IN_STATUS_0
-------- ----------------
a 5

Using a single select statment to get the next row from a table or return the first row if the end of table is reached

I have a table say STAFF like below:
STAFF_NAME
============
ALEX
BERNARD
CARL
DOMINIC
EMMA
Now, I want to write a stored function with a single argument. E.g. GET_NEXT_STAFF(CURRENT_STAFF).
The input and output should be like:
Input | Output
=====================
NULL | ALEX
ALEX | BERNARD
BERNARD | CARL
EMMA | ALEX (Start from the beginning of the table again)
I know how to handle this problem using PL/SQL, but is it possible to deal with this problem with a single select statement?
In the solution below, I assume the rows are ordered alphabetically by names. They may be ordered by another column in the same table (for example by hire date, or by salary, etc. - it doesn't matter) - then the name of that column should be used in the ORDER BY clause of the two analytic functions.
The input name is passed in as a bind variable, :input_staff_name. The solution uses pure SQL, with no need for functions (PL/SQL), but if you must make it into a function, you can adapt it easily.
Edit: In my original answer I missed the required behavior when the input is null. The last line of code (excluding the semicolon) takes care of that. As written currently, the query returns ALEX (or in general the first value in the table) when the input is null, and it returns no rows when the input is not null and not in the table. If instead the requirement is to return the first name when the input is null or not found in the table, then it can be accommodated easily by removing and :input_staff_name is null from the last line.
with
tbl ( staff_name ) as (
select 'ALEX' from dual union all
select 'BERNARD' from dual union all
select 'CARL' from dual union all
select 'DOMINIC' from dual union all
select 'EMMA' from dual
),
prep ( staff_name, next_name, first_name ) as (
select staff_name,
lead(staff_name) over (order by staff_name),
first_value (staff_name) over (order by staff_name)
from tbl
)
select nvl(next_name, first_name) as next_staff_name
from prep
where staff_name = :input_staff_name
or (next_name is null and :input_staff_name is null)
;
Based on the answer from #mathguy I have made a few changes that seem to work. I have added the follow
UNION ALL
SELECT NULL
FROM DUAL
and
WHERE NVL (staff_name, 'X') = NVL (NULL, 'X');
The full code
WITH tbl (staff_name) AS
(SELECT 'ALEX' FROM DUAL
UNION ALL
SELECT 'BERNARD' FROM DUAL
UNION ALL
SELECT 'CARL' FROM DUAL
UNION ALL
SELECT 'DOMINIC' FROM DUAL
UNION ALL
SELECT 'EMMA' FROM DUAL
UNION ALL
SELECT NULL
FROM DUAL),
prep (staff_name,
next_name,
first_name,
last_name) AS
(SELECT staff_name,
LEAD (staff_name) OVER (ORDER BY staff_name),
FIRST_VALUE (staff_name) OVER (ORDER BY staff_name),
LAG (staff_name) OVER (ORDER BY staff_name)
FROM tbl)
SELECT NVL (next_name, first_name) AS next_staff_name
FROM prep
WHERE NVL (staff_name, 'X') = NVL (:input_staff_name, 'X');

Unable to select recent table name from all_tables table

I have a table which contains details of all the tables present in a particular schema. The name of the table is "all_tables". There is a column called table_name which contains the name of all tables.
I have a table named "SBC_RAO_INDEX_30_05_2016_04_99". Here "30_05_2016_04_99" is date with time stamp.
Like wise I have tables with different time stamps as shown below.
SBC_RAO_INDEX_30_05_2016_04_99,
SBC_RAO_INDEX_31_05_2016_04_99,
SBC_RAO_INDEX_01_06_2016_04_99,
SBC_RAO_INDEX_02_06_2016_04_99,
SBC_RAO_INDEX_03_06_2016_04_99
I am trying to fetch the latest table name from all_tables using below query:
select *
from all_tables
WHERE table_name like 'SBC_RAO_INDEX%'
and table_name not like 'SBC_RAO_INDEX_BKP%'
order by table_name desc
But this query is giving me SBC_RAO_INDEX_31_05_2016_04_99 as the first row which is not correct.
Is there any way to fetch the recent table name? Kindly help me in solving this
Try this. Hope it helps.
SELECT
A.*
FROM
(
SELECT
'SBC_RAO_INDEX_30_05_2016_04_99' AS fle
FROM
DUAL
UNION ALL
SELECT
'SBC_RAO_INDEX_31_05_2016_04_99' AS fle
FROM
DUAL
UNION ALL
SELECT
'SBC_RAO_INDEX_01_06_2016_04_99' AS fle
FROM
DUAL
UNION ALL
SELECT
'SBC_RAO_INDEX_02_06_2016_04_99' AS fle
FROM
DUAL
UNION ALL
SELECT
'SBC_RAO_INDEX_03_06_2016_04_99' AS FLE
FROM
DUAL
)
A
ORDER BY
TO_DATE(REPLACE(SUBSTR(A.FLE,15,10),'_','/'),'DD/MM/YYYY') DESC;
because in LIKE the '_' is a special character,
use SUBSTR instead:
SELECT *
FROM all_tables
WHERE SUBSTR(table_name,1,13) ='SBC_RAO_INDEX'
AND SUBSTR(table_name,15,3) <> 'BKP'
ORDER BY table_name DESC
Since the underscore is a special character to LIKE and it matches any single character, escape it to match a literal underscore by defining an escape character like this (you need the ESCAPE clause for each LIKE) and then place that character immediately before the underscore:
select *
from all_tables
WHERE table_name like 'SBC\_RAO\_INDEX%' ESCAPE '\'
and table_name not like 'SBC\_RAO\_INDEX\_BKP%' ESCAPE '\'
order by table_name desc;
Note you can still use the underscore to match a single character in the same string, just escape it when you need to match a literal underscore.
Thanks for your answers.
The below query fullfilled my requirement.
select table_name from all_tables WHERE
table_name like 'SBC_RAO_INDEX_%'
and table_name not like 'SBC_RAO_INDEX_BKP%'
order by TO_DATE(SUBSTR(table_name,15,10),'DD/MM/YYYY') DESC;

How to order by case insensitive ASC or DESC, with DISTINCT and UNION

How to order by case insensitive ASC or DESC for P/L sql 11g. this p/l sql basic question but i can't find good answer in Google please tell how to sort the select result case insensitive
this what i tried
SELECT DISTINCT
asssss,
saas_acc
FROM DUAL
UNION SELECT '--ALL--','ALL' FROM DUAL
ORDER BY upper(asssss) ASC ;
that gave to me ORA-01785: ORDER BY item must be the number of a SELECT-list expression
The simplest option would be to sort by the upper- (or lower-) case column data
ORDER BY UPPER( column_name )
DISTINCT actually filtered the UNIQUE content in the result set, with whatever expressions given in the SELECT clause.
We cannot order it using a Different expression or column name. Please see the example here.
SQL> l
1 SELECT DISTINCT (col1),(col2)
2 FROM
3 ( SELECT 'Hello' col1,'World' col2 FROM DUAL
4 UNION ALL
5 SELECT 'HELLO','WORLD' FROM DUAL
6* )
SQL> /
COL1 COL2
----- -----
HELLO WORLD
Hello World
You can see that DISTINCT is CASE SENSITIVE here.(2 rows displayed)
So, let me Do a UPPER() on both columns.
SQL> l
1 SELECT DISTINCT UPPER (col1),UPPER(col2)
2 FROM
3 ( SELECT 'Hello' col1,'World' col2 FROM DUAL
4 UNION ALL
5 SELECT 'HELLO','WORLD' FROM DUAL
6* )
SQL> /
UPPER UPPER
----- -----
HELLO WORLD
Just 1 row is Displayed, ignoring the case.
Coming back to the actual problem. To order something on a DISTINCT Resultset, it has to be a part of DISTINCT clause's expression/column.
So, When you issue DISTINCT COL1,COl2, the order by may be by COL1 or COL2/.. it cannot be COL3 or even UPPER(COL1) because UPPER() makes a different expression conflicting the expression over DISTINCT.
Finally, Answer for your Question would be
if you want your ORDER to be case-insensitive, DISTINCT also has to the same way! As given below
SELECT DISTINCT
UPPER(asssss),
saas_acc
FROM DUAL
ORDER BY upper(asssss) ASC ;
OR if UNION has to be used, better do this, or same as above one.
SELECT * FROM
(
SELECT DISTINCT asssss as asssss,
saas_acc
FROM DUAL
UNION
SELECT '--ALL--','ALL' FROM DUAL
)
ORDER BY upper(asssss) ASC ;
Out of my own Experience, I had always felt, what ever expression/column is specified in the ORDER BY, it is implicitly taken to final SELECT as well. Ordering is just based on the column number(position) in the result actually . In this situation, DISTINCT COL1,COl2 is already there. When you give ORDER BY UPPER(COL1), it will be tried to append into the SELECT expression, which is NOT possible at all. So, Semantic check itself, would disqualify this query with an Error!
To sort case insensitive you need to set the NLS_COMP to ANSI
NLS_COMP=ANSI
Details: http://www.orafaq.com/node/999
You can use upper or lower functions.
order by upper(columnName)
Update1
Try removing order-by clause from your query which will give you correct error, which is ORA-00904: "SAAS_ACC": invalid identifier. So you can search on google for this error or ask another question on SO.
Also have a look at how to use order by in union.

split string in oracle query

I am trying to fetch phone numbers from my Oracle database table. The phone numbers may be separated with comma or "/". Now I need to split those entries which have a "/" or comma and fetch the first part.
Follow this approach,
with t as (
select 'Test 1' name from dual
union
select 'Test 2, extra 3' from dual
union
select 'Test 3/ extra 3' from dual
union
select ',extra 4' from dual
)
select
name,
regexp_instr(name, '[/,]') pos,
case
when regexp_instr(name, '[/,]') = 0 then name
else substr(name, 1, regexp_instr(name, '[/,]')-1)
end first_part
from
t
order by first_part
;
Lookup substr and instr functions or solve the puzzle using regexp.
I added a table test with one column phone_num. And added rows similar to your description.
select *
from test;
PHONE_NUM
------------------------------
0123456789
0123456789/1234
0123456789,1234
3 rows selected.
select
case
when instr(phone_num, '/') > 0 then substr(phone_num, 0, instr(phone_num, '/')-1)
when instr(phone_num, ',') > 0 then substr(phone_num, 0, instr(phone_num, ',')-1)
else phone_num
end phone_num
from test
PHONE_NUM
------------------------------
0123456789
0123456789
0123456789
3 rows selected.
This generally works. Although it will fail if you have rows with commas and slashes.

Resources