Fetch substring from right side - oracle

I am using oracle. i have a column "ITEM_FINAL" consisting of a string which is a combination of 2 records.
ITEM_FINAL = ITEM_ID + ITEM
I need to segregate ITEM_FINAL and put them into 2 different columns ITEM_ID and ITEM.
However the length of the ITEM_ID is not constant, it can be 1 or 10 or 999 (till 3 digits).
ITEM is constant and it will be 5 digits always.
Eg. ITEM_FINAL = 1256789 (combination of 12 + 56789) or 256789 (combination of 2 + 56789)
I can fetch ITEM details with help of substr
select substr(ITEM_FINAL,-5) from dual;
It will give the last 5 digits (56789) which is constant. How can i fetch the remaining string from 6th position till the start irrespective of length from right hand side for ITEM_ID column

select substr(ITEM_FINAL, 1, length(ITEM_FINAL)-5) ITEM_ID,
substr(ITEM_FINAL,-5) ITEM
from dual;

Related

Referancing value from select column in where clause : Oracle

My tables are as below
MS_ISM_ISSUE
ISSUE_ID ISSUE_DUE_DATE ISSUE_SOURCE_TYPE
I1 25-11-2018 1
I2 25-12-2018 1
I3 27-03-2019 2
MS_ISM_SOURCE_SETUP
SOURCE_ID MODULE_NAME
1 IT-Compliance
2 Risk Assessment
I have written following query.
with rs as
(select
count(ISSUE_ID) as ISSUE_COUNT, src.MODULE_NAME,
case
when ISSUE_DUE_DATE<sysdate then 'Overdue'
when ISSUE_DUE_DATE between sysdate and sysdate + 90 then 'Within 3 months'
when ISSUE_DUE_DATE>sysdate+90 then 'Beyond 90 days'
end as date_range
from MS_ISM_ISSUE issue, MS_ISM_SOURCE_SETUP src
where issue.Issue_source_type = src.source_id
group by src.MODULE_NAME, case
when ISSUE_DUE_DATE<sysdate then 'Overdue'
when ISSUE_DUE_DATE between sysdate and sysdate + 90 then 'Within 3 months'
when ISSUE_DUE_DATE>sysdate+90 then 'Beyond 90 days'
end)
select ISSUE_COUNT,MODULE_NAME, DATE_RANGE,
(select count(ISSUE_COUNT) from rs where rs.MODULE_NAME=MODULE_NAME) as total from rs;
The output of the code is as below.
ISSUE_COUNT MODULE_NAME DATE_RANGE Total
1 IT-Compliance Overdue 3
1 IT-Compliance Within 3 months 3
1 Risk Assessment Beyond 90 days 3
The result is correct till 3rd column. In 4th column what I want is, total of Issue count for given module name. Hence in above case Total column will have value as 2 for first and second row (since there are 2 Issues for IT-Compliance) and value 1 for the third row (since one issue is present for Risk Assessment).
Essentially, I want to achieve is to replace current row's MODULE_NAME in last where clause. How do I achieve this using query?
OK, this condition
where rs.MODULE_NAME=MODULE_NAME
is essentially the same as if you wrote
where MODULE_NAME = MODULE_NAME
which is simply always true (if there are no nulls in module_name).
Try using different table alias for inner query and outer query, e.g.
select count(ISSUE_COUNT) from rs rs2 where rs2.MODULE_NAME=rs.MODULE_NAME
You can also try to use analytic function here, something like
select ISSUE_COUNT,
MODULE_NAME,
DATE_RANGE,
COUNT(ISSUE_COUNT) OVER (PARTITION BY RS.MODULE_NAME) AS TOTAL
from rs
instead of your subquery

Different number of rows for different columns per page

I have a SSRS report in which there are 3 columns each contain 3 different subreports in a table. Requirement is 1st subreport column should return 27 rows, 2nd : 25 rows and 3rd:26 rows. Is it possible in SSRS ? If yes How ?
You can do this.. using row_number and Mod.
I'm simply generating a list of numbers from 1 - 100 below.. lets assume that this is your dataset. Create a new column using row_number and partition it by mod 25 (27 or 26 as you require) against this dataset. Now you have a unique value every X number of rows..
declare #start int = 1
declare #end int = 100
;with mycte as (
select distinct n = number
from master..[spt_values]
where number between #start and #end
)
Select
*
,ROW_NUMBER() OVER (PARTITION BY (mycte.n % 25) ORDER BY (n) )rn
from mycte
order by 1,2
Now in SSRS, against each subreport add this column, add a parent group, grouping by this newly generated row number (RN in this case). Remove any columns that SSRS adds after grouping, but keep the grouping..
Set the group property to pagebreak in between each instance of the groups.. Done!

Creating View with Condititional Criteria

In an Oracle Database version 11g I want to create or replace a view BADGES with the following characteristics:
(1) The view will contain two columns: EMP_ID (NUMBER(9), BADGE_NO(NUMBER(13)).
(2) The view will get data from table Public_View’s following columns: EMP_ID (NUMBER(9)), BLDG_CD(NUMBER(4)), OFFSET_ID(NUMBER(10)).
(3) In the view BADGE_NO is the concatenation of BLDG_CD and OFFSET_ID.
(4) Now the part I am having trouble with: When OFFSET_ID < 1000000 (less than 1 million), I want to left pad OFFSET_ID with 0 (zero) for a total of 7 characters. When OFFSET_ID >= 1000000 (equal to or greater than 1 million), I want to left pad OFFSET_ID with 0 (zero) for a total of 8 characters.
You can put a condition on the sign value in the length of the offset ID minus 7, SIGN(length(OFFSET_ID)-7)
SELECT DECODE(SIGN(length(OFFSET_ID)-7), -1, LPAD(OFFSET_ID, 7, '0'), LPAD(OFFSET_ID, 8, '0'))
FROM your_table;
You can also use the CASE statement if you want,(e.g. CASE SIGN(length(OFFSET_ID)-7) )

Add blank rows between a group of mutliple rows - Oracle

Is there a possibility to add blank rows in a group of data rows dynamically ? I have the below query which fetches data in multiple rows. I want to separate, say add blank row after each 5 rows.
The query :
select php.ref_dcp_key, sum(php.group_booking), count(php.group_booking), 0
from gx_pnr_history ph, gx_pnr_his_prof php
where ph.gmpnr_loc_key = php.gmpnr_loc_key
group by php.ref_dcp_key order by php.ref_dcp_key;
#SandeepGowada, you'd have to create an outer structure for the rows and put in the 6th padding row after every 5 data rows.
I second the view of #juergend that this should really be done in the presentation layer (although often it probably requires no less code overall to do it there than in SQL - but it does frustrate the workings of anything other than a static report, like datagrids that allow re-sorting or filtering)
I've knocked together some untested code (using Oracle syntax) which shows an example of how it's done - how we prepare the base data, then build a table of placeholders for all necessary rows, then join the base data onto the placeholders in the appropriate places. I've made some of the calculations a bit more elaborate to show where the number 5 constant is being used.
Also, I haven't included any code to knock off any surplus padding rows in the final group (i.e. as it stands the number of rows returned will always be a multiple of 6, regardless of the underlying data).
Nor have I included any code regarding the required numbers_table or sequence generator.
WITH base_data AS
(
SELECT
php.ref_dcp_key
,sum(php.group_booking) AS group_booking_sum
,count(php.group_booking) AS group_booking_count
,0 AS zero_value_column
,MOD(ROW_NUMBER() OVER (ORDER BY php.ref_dcp_key) - 1, 5) AS group_line_num
,( (ROW_NUMBER() OVER (ORDER BY php.ref_dcp_key) + (5 - 1)) / 5 ) AS row_group_num
--all appearances of the number 5 constants determine the number of lines per group
FROM
gx_pnr_history /*AS*/ ph
INNER JOIN
gx_pnr_his_prof /*AS*/ php
ON (ph.gmpnr_loc_key = php.gmpnr_loc_key)
GROUP BY
php.ref_dcp_key
)
,row_structure AS
(
SELECT
MOD(number - 1, (5 + 1)) AS group_line_num
,number + ((5 + 1) - 1) / (5 + 1) AS row_group_num
FROM
number_table /*this needs to be a reference either to a numbers table, or a number sequence generator*/
WHERE
number BETWEEN 1 AND ((SELECT MAX(row_group_num) * (5 + 1) FROM base_data))
)
SELECT
ref_dcp_key
,group_booking_sum
,group_booking_count
,zero_value_column
,ROW_NUMBER() OVER (ORDER BY row_structure.row_group_num ASC, row_structure.group_line_num ASC) AS final_order
FROM
row_structure
LEFT JOIN
base_data
ON (base_data.row_group_nun = row_structure.row_group_num)
AND (base_data.group_line_num = row_structure.group_line_num)
ORDER BY
final_order

Substring inside string

Suppose this is my table:
ID STRING
1 'ABC'
2 'DAE'
3 'BYYYYYY'
4 'H'
I want to select all rows that have at least one of the characters in the STRING column somewhere in another row's STRING variable.
For example, 1 and 2 have an A in common and 1 ad 3 have a B in common, but 4 does not have any characters in common with any of the other rows. So my query should return only the first three lines.
I don't need to know with which line it matched.
Thanks!
#A.B.Cade : Good solution but could be done without any distinct nor join.
SELECT * FROM test t1
WHERE EXISTS
(
SELECT * FROM test t2
WHERE t1.id<>t2.id AND
regexp_like(t1.string, '['|| replace(t2.string, '.[]', '\.\[\]')||']')
)
The query won't compare the string with extra rows since it'll stop the comparison as soon as 1 match is found for the current row...
See fiddle.
#GolezTrol's answer is a good one, but here is another approach:
select distinct t1."ID", t1."STRING"
from table1 t1, table1 t2
where t1."ID" <> t2."ID"
and regexp_like(t1."STRING", '['|| t2."STRING"||']')
First take a cartessian product of the table
Then make sure your not comparing the same string to itself
then create a regexp from one string for comparing to the other - [<string1>] means that the string must contain one of the letters in the [ ] which are all from string1
Here is a fiddle
Like this:
select distinct
id, name
from
(select distinct
x.id,
x.NAME,
length(x.NAME) as leng,
substr(x.name, level, 1) as namechar
from
YourTable x
start with
level = 0
connect by
level <= length(x.name)) y
where
exists
(select
'x'
from
YourTable z
where
instr(z.name, y.namechar) > 0 and
z.id <> y.id)
order by
id
What it does:
First, (inner select) use the table with a number generator that returns a number for each letter in the name. Now each record in YourTable is returned Length(Name) times, each with another number. That generated number is used to isolate that letter (substr).
Then (subselect in top level where clause) check if records exist that contain that isolated letter. Distinct is needed, because records are returned more than once if more than one letter matches. You could add namechar to the outer select field list to see the letter that match.

Resources