All tables consisting of numbers less than a fixed number - sql

I am trying to find out all the tables where table names consist of numbers less than a fixed number 16284961 at the end preceded by an underscore for example LOG_16282961.
Sample User_segments table:
Segment_name Bytes
---------------------------------------
LOG_16282961 34
BAL1_16282961 78
BIN$xIDte/qXAFbgU4IeBEeQpw==$0 12
EXCH_16282961 28
C$_0LOG_16282961 17
LOG_16283961 89
BAL1_16283961 10
BIN$xIDte/qWAFbgU4IeBEeQpw==$0 19
EXCH_16283961 90
C$_0LOG_16283961 45
LOG_16284961 21
BAL1_16284961 81
BIN$w1RLAvSeAWjgU4IeBEe2Mw==$0 33
EXCH_16284961 67
C$_0LOG_16284961 39
.......................................
.......................................
Expected Output:
Segment_name Bytes
----------------------
LOG_16282961 34
BAL1_16282961 78
EXCH_16282961 28
C$_0LOG_16282961 17
LOG_16283961 89
BAL1_16283961 10
EXCH_16283961 90
C$_0LOG_16283961 45
.......................
.......................
Query:
SELECT segment_name, bytes/1024/1024 AS "SIZE in MB" FROM user_segments WHERE segment_type='TABLE' AND to_number(regexp_substr(segment_name, '[0-9]+')) < 16284961;
Using above query, although I am getting my result but additionally it also includes following tables which are not required in my output:
BIN$xIDte/qXAFbgU4IeBEeQpw==$0 12
BIN$xIDte/qWAFbgU4IeBEeQpw==$0 19
BIN$w1RLAvSeAWjgU4IeBEe2Mw==$0 33
Can you please help fix my query to get the desired output? Thanks.

Here's one way - using regexp_substr to isolate one or more consecutive digits at the end of the input string, only if immediately preceded by underscore. (If the string does not have that structure, regexp_substr returns null and the filter condition becomes null < [something], which is never true.)
Create mock-up table for testing:
create table test_data (segment_name, bytes) as
select 'LOG_16282961' , 34 from dual union all
select 'BAL1_16282961' , 78 from dual union all
select 'BIN$xIDte/qXAFbgU4IeBEeQpw==$0', 12 from dual union all
select 'EXCH_16282961' , 28 from dual union all
select 'C$_0LOG_16282961' , 17 from dual union all
select 'LOG_16283961' , 89 from dual union all
select 'BAL1_16283961' , 10 from dual union all
select 'BIN$xIDte/qWAFbgU4IeBEeQpw==$0', 19 from dual union all
select 'EXCH_16283961' , 90 from dual union all
select 'C$_0LOG_16283961' , 45 from dual union all
select 'LOG_16284961' , 21 from dual union all
select 'BAL1_16284961' , 81 from dual union all
select 'BIN$w1RLAvSeAWjgU4IeBEe2Mw==$0', 33 from dual union all
select 'EXCH_16284961' , 67 from dual union all
select 'C$_0LOG_16284961' , 39 from dual
;
Query and output:
select *
from test_data
where to_number(regexp_substr(segment_name, '_(\d+)$', 1, 1, null, 1))
< 16284961
;
SEGMENT_NAME BYTES
------------------------------ ----------
LOG_16282961 34
BAL1_16282961 78
EXCH_16282961 28
C$_0LOG_16282961 17
LOG_16283961 89
BAL1_16283961 10
EXCH_16283961 90
C$_0LOG_16283961 45

If query you wrote works, just omit tables you don't want. Those you mentioned have been dropped and are now in recycle bin. So, either purge recyclebin before running the query, or use additional condition, e.g.
SELECT segment_name, bytes / 1024 / 1024 AS "SIZE in MB"
FROM user_segments
WHERE segment_type = 'TABLE'
AND substr(segment_name, 1, 4) <> 'BIN$' --> this
AND TO_NUMBER (REGEXP_SUBSTR (segment_name, '[0-9]+')) < 16284961;

Related

How to generate values between 2 values?

My data looks like below
with test(col) as (
select '01-06' from dual union all
select '45-52' from dual
) select col from test ;
Required OP
COL
01
02
.
.
.
06
45
46
.
.
52
Actually my table count is 20 thousand. I used connect by but its very slow.
You can generate values using recursive query:
with test(col) as (
select '01-06' from dual union all
select '45-52' from dual
), bounds (l,u) as (
select to_number(substr(col,1,2)), to_number(substr(col,4,2)) from test
), r (l,u) as (
select l,u from bounds
union all
select r.l + 1, r.u from r where r.l < r.u
)
select to_char(l,'00') from r order by l;
(edit substr expressions appropriately if any value is not 2-digit)
Saying "I used connect by but its very slow" without posting code you wrote doesn't help much. I presume you did it wrong, i.e. got too many duplicate values which slowed things down. See if this connect by option helps.
SQL> with test (col)
2 as
3 (select '1-6' from dual
4 union all
5 select '45-52' from dual
6 )
7 select lpad(to_number(substr(col, 1, instr(col, '-') - 1)) + column_value - 1, 2, '0') val
8 from test cross join
9 table(cast(multiset(select level from dual
10 connect by level <= to_number(substr(col, instr(col, '-') + 1)) -
11 to_number(substr(col, 1, instr(col, '-') - 1)) + 1
12 ) as sys.odcinumberlist));
VAL
---
01
02
03
04
05
06
45
46
47
48
49
50
51
52
14 rows selected.
SQL>

Rows to columns when data sometimes is missing

Transform data from rows to columns. I've got two ID rows, and one text VARCHAR2 type row. But one of the ID rows not always the same. Sometime missing the data.
I tried with PIVOT and GROUP BY until now this gave me only errors.
SELECT prj_id, udn_id, txt_value
FROM TBL
GROUP BY tbl.prj_id;
I would like transform this:
(The empty line is only for the better visibility)
PRJ_ID UDN_ID TXT_ VALUE
8344 82 13/10/2009
8344 64 E S
8344 178 End
8364 82 12/10/2009
8364 64 A M
8364 89 M
8364 178 Internal
8335 82 05/10/2009
8335 64 E S
8335 89 N
8335 178 End
8377 82 13/10/2009
8377 64 Z D
8377 89 N;M
8377 178 Internal
to this:
82 64 89 178
8344 13/10/2009 E S N/A End
8364 12/10/2009 A M M Internal
8335 05/10/2009 E S N End
8377 13/10/2009 Z D N;M Internal
Any idea how can solve this with SQL?
The oldfashioned way (prior to PIVOT) was to aggregate value using DECODE (or CASE, for better readability). Here's an example (lines 16 onwards are what you're looking for):
SQL> with tbl (prj_id, udn_id, txt_value) as
2 (select 8344, 82, '13/10/2009' from dual union all
3 select 8344, 64, 'E S' from dual union all
4 select 8344, 178, 'End' from dual union all
5 --
6 select 8364, 82, '12/10/2009' from dual union all
7 select 8364, 64, 'A M' from dual union all
8 select 8364, 89, 'M' from dual union all
9 select 8364, 178, 'Internal' from dual union all
10 --
11 select 8335, 82, '05/10/2009' from dual union all
12 select 8335, 64, 'E S' from dual union all
13 select 8335, 89, 'N' from dual union all
14 select 8335, 178, 'End' from dual
15 )
16 select prj_id,
17 max(case when udn_id = 82 then txt_value end) "82",
18 max(case when udn_id = 64 then txt_Value end) "64",
19 max(case when udn_id = 89 then txt_value end) "89",
20 max(case when udn_id = 178 then txt_Value end) "178"
21 from tbl
22 group by prj_id;
PRJ_ID 82 64 89 178
---------- ---------- ---------- ---------- ----------
8335 05/10/2009 E S N End
8344 13/10/2009 E S End
8364 12/10/2009 A M M Internal
SQL>
This is achievable using the PIVOT in oracle.
Please use below and let me know in case of any queries.
select * from (
with all_data as(
select '8344' prj_id, 82 id, '40099' txt_val from dual union all
select '8344' prj_id, 64 id, 'E S' txt_val from dual union all
select '8344' prj_id, 178 id, 'End' txt_val from dual union all
select '8364' prj_id, 82 id, '40098' txt_val from dual union all
select '8364' prj_id, 64 id, 'A M' txt_val from dual union all
select '8364' prj_id, 89 id, 'M' txt_val from dual union all
select '8364' prj_id, 178 id, 'Internal' txt_val from dual union all
select '8335' prj_id, 82 id, '40091' txt_val from dual union all
select '8335' prj_id, 64 id, 'E S' txt_val from dual union all
select '8335' prj_id, 89 id, 'N' txt_val from dual union all
select '8335' prj_id, 178 id, 'End' txt_val from dual union all
select '8377' prj_id, 82 id, '40099' txt_val from dual union all
select '8377' prj_id, 64 id, 'Z D' txt_val from dual union all
select '8377' prj_id, 89 id, 'N;M' txt_val from dual union all
select '8377' prj_id, 178 id, 'Internal' txt_val from dual)
select prj_id,id,txt_val from all_data)
pivot
(max(txt_val)
for id in (82 as "82_val", 64 as "64_val", 89 as "89_val", 178 as "178_val"))
order by 1
;
I am new to Oracle syntaxes. So, I have written in SQL server syntax. Hope this helps you:
CREATE TABLE Project(PRJ_ID int, UDN_ID INT, TXT_VALUE varchar(100));
INSERT INTO Project VALUES (8344,82,'E S'),(8344,69,'A M'),(8364,82,'End'),(8364,59,'Internal');
DECLARE #columns NVARCHAR(MAX), #columns1 NVARCHAR(MAX), #sql NVARCHAR(MAX);
--selecting distinct values and concatenating to get a result like [82],[69],[82]...
SELECT #columns1 = STUFF((
SELECT DISTINCT ',' + '['+ CAST(UDN_ID AS VARCHAR) + ']' FROM Project
FOR XML PATH('')
), 1, 1, '')
FROM Project;
--using that dynamic column string in the pivot query string
SET #sql = 'SELECT PRJ_ID,' + #columns1 + ' FROM
(
SELECT * FROM Project
) AS src
PIVOT
(
MAX(TXT_VALUE) FOR src.UDN_ID IN ('+ #columns1
+ ')
) AS p;';
--executing the pivot query
EXEC sp_executesql #sql;

Oracle query to convert a value with brackets to negitive number

I have a string column that has the values like below
Column A
(9167)
1042
21463
9979
(26351)
I need the output like below -
Output
-9167
1042
21463
9979
-26351
I need to trim the brackets and replace that with '-' Symbol by using update statement. Is there a way we can do it with a query?
How about this:
with demo (column_a) as
( select '(9167)' from dual union all
select '1042' from dual union all
select '21463' from dual union all
select '9979' from dual union all
select '(26351)' from dual )
select column_a
, case
when trim(column_a) like '(%)' then
to_number(regexp_replace(column_a,'[()]')) * -1
else to_number(column_a)
end as result
from demo;
COLUMN_A RESULT
-------- ----------
(9167) -9167
1042 1042
21463 21463
9979 9979
(26351) -26351
Use Translate 'from characters', 'to characters'
As the user guide states, "TRANSLATE lets you make several single-character, one-to-one substitutions in one operation."
One just maps the replacement characters as follows:
from: ()
to: -
where the 1st from character ( is mapped to the 1st to character -
where the 2nd from character ) is mapped to the 2nd to character, which doesn't exist so is null
SCOTT#db>WITH tst AS (
2 SELECT
3 '(9167)' val FROM
4 dual
5 union all
6 select
7 '1042' val FROM
8 dual
9 union all
10 select
11 '21463' val FROM
12 dual
13 union all
14 select
15 '9979' val FROM
16 dual
17 union all
18 select
19 '(26351)' val
20 FROM
21 dual
22 ) SELECT
23 translate(t.val,'()','-')
24 FROM
25 tst t;
TRANSLA
-------
-9167
1042
21463
9979
-26351

Sql range query

Query returning 2 values from table TBL_CHARGES:
Range_in_hrs Range_to_hours charges
4 48 5
48 70 10
70 90 20
Select charges from table if range 47.59 is passed the return charge should be 5. If 48.00 is passed the charges will be 5.
If 48.01 is passed the charges should be 10.
I am trying this
SELECT *
FROM TBL_CHARGES
WHERE 48.00 between Range_in_hrs and Range_to_hours
But it does not works.
Sounds like you need to avoid using BETWEEN and instead use explicit ranges, like so:
select *
from tbl_charges
where 48 > range_in_hrs
and 48 <= range_to_hours;
And here's an example that shows the output you might get with various different values:
with tbl_charges as (select 4 range_in_hours, 48 range_to_hours, 5 charges from dual union all
select 48 range_in_hours, 70 range_to_hours, 10 charges from dual union all
select 70 range_in_hours, 90 range_to_hours, 20 charges from dual),
vals as (select 4 val from dual union all
select 4.01 val from dual union all
select 47.59 val from dual union all
select 48 val from dual union all
select 48.01 val from dual union all
select 70 val from dual union all
select 71 val from dual)
select vals.val,
tc.charges
from vals
left outer join tbl_charges tc on (vals.val > tc.range_in_hours and vals.val <= tc.range_to_hours);
VAL CHARGES
---------- ----------
4
4.01 5
47.59 5
48 5
48.01 10
70 10
71 20
My problem got solved by this query.
SELECT *
FROM TBL_CHARGES
WHERE 48.00 between Range_in_hrs||'.01' and Range_to_hours||'.00'
SELECT charges
FROM TBL_CHARGES
WHERE ceil(to_number('48.01')) between Range_in_hrs and Range_to_hours
Use Replace and Ceil.

Sorting Alphanumeric data in Oracle

I have an alphanumeric data like:
1
1a
1b
2
2b
10
10a
If I sort this data, output will be like:
1
1a
10
10a
2
2b
But I want output as:
1
1a
2
2b
10
10a
How to get this output with Oracle command?
So, as I understand, you want to sort by numeric part of your data. For this purpose you can use regular expression (to extract the numeric part) like this:
SQL> select str from
2 (
3 select '1' str from dual union all
4 select '1a' from dual union all
5 select '1b' from dual union all
6 select '2' from dual union all
7 select '2b' from dual union all
8 select '10' from dual union all
9 select '10a' from dual
10 ) t
11 order by to_number(regexp_substr(str, '^[[:digit:]]*')), str
12 /
STR
---
1
1a
1b
2
2b
10
10a
You can also do the same by separating number and alphanumeric sorting order in order by clause. check below example:
SELECT tt.qdef_grid
FROM qgdm_qdef tt
ORDER BY to_number(substr(tt.qdef_grid,2,2)), substr(tt.qdef_grid,1,1);