Oracle query looking for particular string format - oracle

Am working with an Oracle 11g db in which I need to run a query that returns all rows with values in a specific format.
I.e., I need to find all rows with a value like 'abc1234'. The actual values aren't important....what I need is to find all rows with the first 3 characters being alpha and the subsequent 4 characters all being numeric.
Any input would be much appreciated.

Might not be exact since I don't have an Oracle server handy to test but something like this should get you started in the right direction:
SELECT * FROM your_table WHERE REGEXP_LIKE(your_column, '([a-z]\3[0123456789]\4', 'i')
This will check all rows in your table where the specified column has any alphabet character A to Z three times followed by 4 numbers and return that list. The 'i' at the end just says ignore case on the alphabet part. You can choose to not have that option if you so wish.
Here are a couple links as well with more information on the regexp_like syntax:
Oracle SQL - REGEXP_LIKE contains characters other than a-z or A-Z
https://docs.oracle.com/cd/B28359_01/server.111/b28286/conditions007.htm#SQLRF00501

Try it this will work definitely:
Let's take a sample example:
For example, create a sample table
CREATE TABLE bob (
empno VARCHAR2(10) NOT NULL,
ename VARCHAR2(15) NOT NULL,
ssn VARCHAR2(10) NOT NULL);
Insert data into that table
Insert into bob ( empno,ename,ssn) values ('abC0123458','zXe5378023','0pl4783202');
Insert into bob ( empno,ename,ssn) values ('0123abcdef','a12dldfddd','Rns0101010');
Query to select the all the columns
select * from bob
where length(trim(translate(substr(empno,1,3),'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',' '))) IS NULL
AND
length(trim(translate(substr(empno,4,4),'0123456789',' '))) IS NULL;
To do the same thing on multiple columns use union operator
select * from bob
where length(trim(translate(substr(empno,1,3),'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',' '))) IS NULL
AND
length(trim(translate(substr(empno,4,4),'0123456789',' '))) IS NULL;
union
select * from bob
where length(trim(translate(substr(ename,1,3),'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',' '))) IS NULL
AND
length(trim(translate(substr(ename,4,4),'0123456789',' '))) IS NULL;

Related

select from the table name values after _ using oracle sql

Suppose if the table name is ABC_XYZ_123. I want to extract the integer values after _.
The output should be integer values after _.
In the above case, the output should be 123.
I have used the below sql query.
select from table_name like 'XXX_%';
But I am not getting required output. Can anyone help me with this query.
Thanks
Using REGEXP_SUBSTR with a capture group we can try:
SELECT REGEXP_SUBSTR(name, '_(\d+)$', 1, 1, NULL, 1)
FROM yourTable;
The question is somewhat unclear:
it looks as if you're looking for table names that contain number at the end, while
query you posted suggests that you're trying to select those numbers from one of table's columns
I'll stick to
Suppose if the table name is ABC_XYZ_123
If that's so, it is the data dictionary you'll query. USER_TABLES contains that information.
Let's create that table:
SQL> create table abc_xyz_123 (id number);
Table created.
Query selects numbers at the end of table names, for all my tables that end with numbers.
SQL> select table_name,
2 regexp_substr(table_name, '\d+$') result
3 from user_tables
4 where regexp_like(table_name, '\d+$');
TABLE_NAME RESULT
-------------------- ----------
TABLE1 1
TABLE2 2
restore_point-001 001
ABC_XYZ_123 123 --> here's your table
SQL>
Apparently, I have a few of them.

Can't use oracle associative array in object (for custom aggregate function)

Background : My purpose is to write an aggregate function in oracle to make a string contains number of occurrence of each element. For example "Jake:2-Tom:3-Jim:5" should means 2 times occurrence for Jake, 3 times for Tom and 5 times for Jim. So for writing a custom aggregate function I should write an object implements ODCIAggregate routines. And also a Map like data structure for counting each element occurrences. Only Map like data structure in oracle is associative array.
Problem : Unfortunately I can't know any approach to use associative arrays in object. I tried these approaches:
1 – Create a generic type for associative array and use it in object. Oracle doesn't let creating generic associative array types.
CREATE TYPE STR_MAP IS TABLE OF NUMBER INDEX BY VARCHAR2(100);
This get following error :
PLS-00355: use of pl/sql table not allowed in this context
2 – Create map like type in a package and use it in object. Oracle lets creating an associative array in a package, but doesn’t let using an 'in package type' in object. I checked all issues about grant execute on package or make a synonym for 'in package type'. But there is no way for use 'in package type' in object declaration.
P.S. 1 :
Of course we can do it for one column by nested group by. But I prefer to do it for many columns with only agg-func. It is very useful agg-func and I wonder why nobody wrote something like this before. For many columns we have limited number of distinct values, and with such an agg-func we can simply summarize all of them. For example if we had such a agg-func named ocur_count(), we can simply analyze an collection of transactions like this :
select ocur_count(trans_type), ocur_count(trans_state), ocur_count(response_code), ocur_count(something_status) from transaction;
You can use listagg and a simple group by with a count to get what you need (Note the listagg output is limited in size to 4k chars). Here I'm counting occurrences of first names, using ',' as the separator between names and ':' as the separator for count:
SQL> create table person_test
(
person_id number,
first_name varchar2(50),
last_name varchar2(50)
)
Table created.
SQL> insert into person_test values (1, 'Joe', 'Blow')
1 row created.
SQL> insert into person_test values (2, 'Joe', 'Smith')
1 row created.
SQL> insert into person_test values (3, 'Joe', 'Jones')
1 row created.
SQL> insert into person_test values (4, 'Frank', 'Rizzo')
1 row created.
SQL> insert into person_test values (4, 'Frank', 'Jones')
1 row created.
SQL> insert into person_test values (5, 'Betty', 'Boop')
1 row created.
SQL> commit
Commit complete.
SQL> -- get list of first names and counts into single string
SQL> --
SQL> -- NOTE: Beware of size limitations of listagg (4k chars if
SQL> -- used as a SQL statement I believe)
SQL> --
SQL> select listagg(person_count, ',')
within group(order by person_count) as person_agg
from (
select first_name || ':' || count(1) as person_count
from person_test
group by first_name
order by first_name
)
PERSON_AGG
--------------------------------------------------------------------------------
Betty:1,Frank:2,Joe:3
1 row selected.
NOTE: If you do run into a problem with string concatenation too long (exceeds listagg size limit), you can choose to return a CLOB using xmlagg:
-- this returns a CLOB
select rtrim(xmlagg(xmlelement(e,person_count,',').extract('//text()') order by person_count).GetClobVal(),',')
from (
select first_name || ':' || count(1) as person_count
from person_test
group by first_name
order by first_name
);
Hope that helps
EDIT:
If you want counts for multiple columns (firstname and lastname in this example), you can do:
select
typ,
listagg(cnt, ',') within group(order by cnt)
as name_agg
from (
-- FN=FirstName, LN=LastName
select 'FN' as typ, first_name || ':' || count(1) as cnt
from person_test
group by first_name
union all
select 'LN' as typ, last_name || ':' || count(1) as cnt
from person_test
group by last_name
)
group by typ;
Output:
"FN" "Betty:1,Frank:2,Joe:3"
"LN" "Blow:1,Boop:1,Jones:2,Rizzo:1,Smith:1"
I'd also note that you probably can create a custom aggregate function to do this, I just prefer to stick with built in functionality of SQL first if it can solve my problem.

How to only select existing values from oracle?

I have a table with a massive number of columns. So many, that when I do SELECT * I can't even see any values because all the columns fill up the screen. I'd like to do something like this:
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND <THIS COLUMN> IS NOT NULL
Is this possible? Note: VALUE is not a column.
There are so many questions on SO that ask this same question, but they have some bizarre twist, and the actual question is not answered.
I've tried:
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND VALUE NOT NULL
*
Invalid relational operator
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND VALUE <> ''
*
'VALUE': invalid identifier
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND COLUMN NOT NULL
*
Missing Expression
Bonus Questions:
Is there any way to force Oracle to only show one output screen at a time?
Is there a variable to use in the WHERE clause that relates to the current column? Such as: WHERE this.column = '1', where it would check each column to match that expression?
Is there any way to get back your last command in Oracle? (I have to remote into a Linux box running Oracle - it's all command line - can't even copy/paste, so I have to type every command by hand, with a wonky connection, so it's taking an extremely long time to debug this stuff)
If you are trying to find all the non null column values for a particular record you could try an unpivot provided all the columns you are unpivoting have the same data type:
SELECT *
FROM (select * from my_table where name like '%unique value%')
UNPIVOT [include nulls] (col_value FOR col_name IN (col1, col2, ..., coln))
with the above code null values will be excluded unless you include the optional include nulls statement, also you will need to explicitly list each column you want unpivoted.
If they don't all have the same data type, you can use a variation that doesn't necessarily prune away all the null values:
select *
from (select * from my_table where name like '%unique value%')
unpivot ((str_val, num_val, date_val)
for col_name in ((cola, col1, date1)
,(colb, col2, date2)
,(colc, col3, date1)));
You can have a fairly large set of column groups, though here I'm showing just three, one for each major data type, with the IN list you need to have a column listed for each column in your column group, though you can reuse columns as shown by the date_val column where I've used date1 twice. As an alternative to reusing an existing column, you could use a dummy column with a null value:
select *
from (select t1.*, null dummy from my_table t1 where name like '%unique value%')
unpivot ((str_val, num_val, date_val)
for col_name in ((dummy, col1, date1)
,(colb, dummy, date2)
,(colc, col3, dummy)));
Have tried this?
SELECT * FROM my_table WHERE NAME LIKE '%unique name%' AND value IS NOT NULL;
Oracle / PLSQL: IS NOT NULL Condition
For row number:
SELECT field1, field2, ROW_NUMBER() OVER (PARTITION BY unique_field) R WHERE R=1;
Usually in Linux consoles you can use arrow up&down to repeat the last sentence.

How to show star at first two character of a string in oracle query?

Example if an ID is 1213 i want show **13.
If it's a number
select '**' || substr(to_char(id),3)
from my_table
Or, if it's already a character
select '**' || substr(id,3)
from my_table
This concatenates ** onto the beginning of the string, using the Oracle concatenation operator || and removes the first two characters of the id using substr.
Here's a SQL Fiddle to demonstrate.
If you don't want to sacrifice performance too much, to mask first two characters you can use-
SQL> select regexp_replace('1213','(.)2','**') from dual; --if VARCHAR
MASKED
------------
**13
SQL> select regexp_replace(1213,'(.)2','**') from dual; --if NUMBER
MASKED
------------
**13
REGEXP_REPLACE will work alike on NUMBER and VARCHAR so you save some conversion time there.
Consecutively, you can create a Function Based Index on the regexp function operation to optimize the query like (considering you would always want to mask only first two characters of ID) -
CREATE INDEX
mask_id
ON
table_name
(regexp_replace(id,'(.)2','**'));

How to generate alphanumeric id in Oracle

In my vb application I want an autogenerated id of alphanumeric characters, like prd100. How can I increment it using Oracle as backend?
Any particular reason it needs to be alphanumeric? If it can just be a number, you can use an Oracle sequence.
But if you want just a random string, you could use the dbms_random function.
select dbms_random.string('U', 20) str from dual;
So you could probably combine these 2 ideas (in the code below, the sequence is called oid_seq):
SELECT dbms_random.string('U', 20) || '_' || to_char(oid_seq.nextval) FROM dual
There are two parts to your question. The first is how to create an alphanumeric key. The second is how to get the generated value.
So the first step is to determine the source of the alpha and the numeric components. In the following example I use the USER function and an Oracle sequence, but you will have your own rules. I put the code to assemble the key in a trigger which is called whenever a row is inserted.
SQL> create table t1 (pk_col varchar2(10) not null, create_date date)
2 /
Table created.
SQL> create or replace trigger t1_bir before insert on t1 for each row
2 declare
3 n pls_integer;
4 begin
5 select my_seq.nextval
6 into n
7 from dual;
8 :new.pk_col := user||trim(to_char(n));
9 end;
10 /
Trigger created.
SQL>
The second step requires using the RETURNING INTO clause to retrieve the generated key. I am using SQL*PLus for this example. I confess to having no idea how to wire this syntax into VB. Sorry.
SQL> var new_pk varchar2(10)
SQL> insert into t1 (create_date)
2 values (sysdate)
3 returning pk_col into :new_pk
4 /
1 row created.
SQL> print new_pk
NEW_PK
--------------------------------
APC61
SQL>
Finally, a word of warning.
Alphanumeric keys are a suspicious construct. They reek of "smart keys" which are, in fact, dumb. A smart key is a value which contains multiple parts. At somepoint you will find yourself wanting to retrieving all rows where the key starts with 'PRD', which means using SUBSTR() or LIKE. Even worse someday the definition of the smart key will change and you will have to cascade a complicated update to your table and its referencing foreign keys. A better ides is to use a surrogate key (number) and have the alphanumeric "key" defined as separate columns with a UNIQUE composite constraint to enforce the business rule.
SQL> create table t1 (id number not null
2 , alpha_bit varchar2(3) not null
3 , numeric_bit number not null
4 , create_date date
5 , constraint t1_pk primary key (id)
6 , constraint t1_uk unique (alpha_bit, numeric_bit)
7 )
8 /
Table created.
SQL>

Resources