See the below data below first, i need to calculate the columns HUB_NM, PRODUCT_NM and STRIP_NM from the first 2 columns as described.
DEAL_ORIGINATION EXCH_SYMBOL HUB_NM PRODUCT_NM STRIP_NM
---------------- ---------------------------------------------- ---------- --------------------- ------------
TT_ICE IPE e-Gas Oil DEC 2010 IPE e-Gas Oil DEC 2010
GLOBEX HO DEC 2010 HO DEC 2010
ICE NG Firm Phys, ID, GDD - Transco-45 - Next Day Gas Transco-45 NG Firm Phys, ID, GDD Next Day Gas
STUSCO_ICE Brent Crude Futures - North Sea - Dec12 Brent Crude Futures DEC12
I can't work out how to do it. I know I should use SUBSTR and INSTR but I can't figure it out.
A) How to get HUB_NM column value from EXCH_SYMBOL?
If T.DEAL_ORIGINATION = 'ICE'
then
Find 1st space dash space
Find 2nd space dash space
Display the word in between, no space at the end
elsif T.DEAL_ORIGINATION in ('GLOBEX', 'TT_ICE', 'STUSCO_ICE')
then
null;
end if;
B) How to get PRODUCT_NM column value from EXCH_SYMBOL?
If T.DEAL_ORIGINATION in ( 'ICE', 'STUSCO_ICE')
then
Display from 1st character to the 1st dash, no space at the end
elsif T.DEAL_ORIGINATION in ('GLOBEX', 'TT_ICE',)
then
Remove -9 caharacters from the end of the word and display the fornt word, no space at the end
end if;
C) How to get STRIP_NM column value from EXCH_SYMBOL?
If T.DEAL_ORIGINATION in ( 'ICE', 'STUSCO_ICE')
then
Find the 2nd space dash space
Display from then on to the end of the word, no space at the end
elsif T.DEAL_ORIGINATION in ('GLOBEX', 'TT_ICE',)
then
Display the last -8 caharacters from the end of the word, no space at the end
end if;
Let's start adding some instructions to create a sample data.
CREATE TABLE mytab
(
DEAL_ORIGINATION VARCHAR2(100),
EXCH_SYMBOL VARCHAR2(100),
HUB_NM VARCHAR2(100),
PRODUCT_NM VARCHAR2(100),
STRIP_NM VARCHAR2(100)
);
INSERT INTO mytab (DEAL_ORIGINATION, EXCH_SYMBOL, HUB_NM, PRODUCT_NM, STRIP_NM)
VALUES ('TT_ICE', 'IPE e-Gas Oil DEC 2010', null, 'IPE e-Gas Oil', 'DEC 2010' );
INSERT INTO mytab (DEAL_ORIGINATION, EXCH_SYMBOL, HUB_NM, PRODUCT_NM, STRIP_NM)
VALUES ('GLOBEX', 'HO DEC 2010',null, 'HO', 'DEC 2010' );
INSERT INTO mytab (DEAL_ORIGINATION, EXCH_SYMBOL, HUB_NM, PRODUCT_NM, STRIP_NM)
VALUES ('ICE NG','Firm Phys, ID, GDD - Transco-45 - NEXT DAY Gas', 'Transco-45', 'NG Firm Phys, ID, GDD', 'NEXT DAY Gas');
INSERT INTO mytab (DEAL_ORIGINATION, EXCH_SYMBOL, HUB_NM, PRODUCT_NM, STRIP_NM)
VALUES ('STUSCO_ICE', 'Brent Crude Futures - North Sea - Dec12', null, 'Brent Crude Futures', 'DEC12');
Sure you have to make a lot of work figuring out how the instr and substr results will be. Moreover you will never figure it out by just thinking or writing down tons of parentheses.
My advice is to write a temporary select instruction with partial results, like the following:
SELECT deal_origination, exch_symbol,
INSTR(exch_symbol,' - ')+3 as string_start,
INSTR( SUBSTR(EXCH_SYMBOL,INSTR(exch_symbol,' - ')+3) , ' - ')-1 string_length ,
SUBSTR(exch_symbol, INSTR(exch_symbol,' - ')+3, INSTR( SUBSTR(EXCH_SYMBOL,INSTR(exch_symbol,' - ')+3) , ' - ')-1 ) as RESULT
FROM mytab
Please note that the RESULT column is made using the same expressions as string_start and string_length columns.
This also answers to the A question
This will give you the initial results, so you will be able to figure out what will happen inside the expression. Then put everything into a DECODE instruction
Example 2:
decode ( DEAL_ORIGINATION,
'ICE', 'results in case of ICE',
'GLOBEX', 'results in case of GLOBEX',
null)
-- the last null is the default condition
Finally to remove 9 characters to the end of a work use the LENGTH function
Example 3:
-- this removes the last 6 characters from the hello world string
select substr ( 'hello world', 1, length('hello world) - 6 )
Accept apologies for being unable to test the Oracle code on an actual machine.
Related
I need to calculate age for the people and their birthdates are saved in varchar2 like 19900130, and some people don't have their birthdates recorded and default value is 00000000.
Here is my code:
SELECT
e.id_number,
e.birth_dt,
(CASE WHEN SUBSTR(e.birth_dt, 1, 4) = '0000' THEN 0
WHEN SUBSTR(e.birth_dt, 1, 4) <> '0000' THEN
ROUND(MONTHS_BETWEEN(SYSDATE, TO_DATE(e.birth_dt, 'YYYYMMDD')) / 12)
ELSE -1
END) age
FROM employee e
The error is:
ORA-01843: Not a valid month
Is anything wrong? I couldn't figure out.
Is anything wrong? Yes, your case is not covering the possibility that some strings have something other than 01, 02, ..., 12 in character positions 5 and 6. Likewise, your case is not covering the possibility that the day of the month character positions are something other than 01, 02, ... 31 (and the covering of the possibility that a day of the month is not valid for a particular month).
If I were you, I'd add a proper date column, modify the app to populate both columns, fix the app so that it stops putting bad data into the table, decide what to do with the bad data, modify the app to stop populating the varchar2 column, and then drop the varchar2 column.
I have an Interactive Report which I'm generating using a collection.
select apex_item.checkbox(1,'obj_name') ' ',
col 01,
col 02
from apex_collections where collection_name='XYZ';
The table on which this report is being generated has a composite primary key,
so when the user selects multiple checkboxes, I'm not able to figure out how to identify which all rows were selected by user. This is because according to my knowledge, through p_value in apex_item.checkbox(p_idx,p_value) I can just pass one column/field/item. But the requirement is to pass both obj_name and col 01 back to the pl/sql code.
To explain it better, I have an on submit process associated to it.
FOR I in 1..APEX_APPLICATION.G_F01.COUNT LOOP
DELETE FROM abc
WHERE obj_name = (APEX_APPLICATION.G_F01(i))
AND tab_col = col 01;
END LOOP;
So how can I send the value of col 01 of the selected checkboxes to the above process is what my question is. Any help would be great.
A better approach which I've found now is using rownum as unique value, that actually reduces a lot of logic in my code. Just calling it out.
Could you concatenate the obj_name and col_name?
select apex_item.checkbox(1,'obj_name-'||col_01) ' ', from apex_collections where collection_name='XYZ';
Then in the processing section
FOR I in 1..APEX_APPLICATION.G_F01.COUNT LOOP
my_object_name := substr( G_F01(i), 1, instr( G_F01(i), '-' ) - 1 );
my_column_name := substr( G_F01(i), instr( G_F01(i), '-' ) + 1 );
DELETE FROM abc WHERE obj_name = my_object_name AND tab_col = my_column_name;
END LOOP;
In a view i under the SOURCE column I have the following values.
SRC - TERM - randomtext - LOCATION (Just a FYI on the format of the source column)
ABC DE RANDOMJIBBERISH MORE RANDOMJIBBERISH FORWARD
ARY HES RANDOMJIBBERISH MORE RANDOMJIBBERISH BACKWARD
IGHE UER RANDOMJIBBERISH MORE RANDOMJIBBERISH LEFT
Now I have a query that needs to lookup on that view BASED on the source. This one works perfectly fine.
SELECT
t.DATE_, t.PX_LAST
FROM
THIS.TABLE_NEW t
WHERE
t.DATE_ >= '2003-03-02'
AND t.DATE_ <= '2013-03-02'
AND t.SOURCE LIKE 'ABC DE % FORWARD' --Where the magic happens
AND t.SOURCE LIKE '%'||'1M'||'%'
AND t.PX_LAST is NOT NULL
ORDER BY
t.DATE_ ASC;
Now, the issue is, when I try to implement this in a stored procedure, I will need to insert the percent sign in the parameters I get. This doesn't work, particularly the part where it looks for the source using the inSource
PROCEDURE Get_It
(
inSource VARCHAR2,
inStartDate DATE,
inEndDate DATE,
inLength VARCHAR2,
inRC1 OUT SYS_REFCURSOR
) AS
BEGIN
OPEN inRC1 FOR
SELECT t.DATE_, t.PX_LAST
FROM THIS.TABLE_NEW t WHERE
t.DATE_ >= inStartDate
AND t.DATE_ <= inEndDate
AND t.SOURCE LIKE inSource --Where the magic needs to happen
AND t.SOURCE LIKE '%'||length||'%'
AND t.PX_LAST is NOT NULL
ORDER BY t.DATE_ ASC;
END GET_IT;
So basically I need to insert a percent sign in the MIDDLE of the string (inSource), between the last and second-last word, at all times. I was able to do it in the query because I can manually put it in the string, but in the actual stored procedure I don't know how I can manipulate the string.
Assuming you want to pass in a value of inSource like 'ABC DE FORWARD' and have the procedure translate that to 'ABC DE % FORWARD' - with the % always between the second and third word - then you can mess around with chopping up and reconstructing the string, or you can do a simple regexp_replace():
AND t.SOURCE LIKE regexp_replace(inSource, ' ', ' % ', 1, 2)
AND t.SOURCE LIKE '%'||inLength||'%'
This replaces a space with a space-padded percentage sign, starting as position 1 (i.e. the start of the string) and only applying to the second instance - so it skips over the first space and only affects the one between the second and third words.
To demonstrate this:
select regexp_replace('ABC DE FORWARD', ' ', ' % ', 1, 2)
from dual;
REGEXP_REPLACE('
----------------
ABC DE % FORWARD
Looks to me that your query is fine but your inLength parameter is not being used correctly in the cursor definition.
Based on your edit clarification there are two possible solutions.
First option: Pass inSource as two varchars which would be all of the string up until the space and then the last word
PROCEDURE Get_It
(
inSourceFirst VARCHAR2,
inSourceLast VARCHAR2,
inStartDate DATE,
inEndDate DATE,
inLength VARCHAR2,
inRC1 OUT SYS_REFCURSOR
) AS
BEGIN
OPEN inRC1 FOR
SELECT t.DATE_, t.PX_LAST
FROM THIS.TABLE_NEW t WHERE
t.DATE_ >= inStartDate
AND t.DATE_ <= inEndDate
AND t.SOURCE LIKE inSourceFirst || '%' || inSourceLast
AND t.SOURCE LIKE '%'|| inLength ||'%'
AND t.PX_LAST is NOT NULL
ORDER BY t.DATE_ ASC;
END GET_IT;
Second option: Use regexp_substr() function More here. Your inSource string would then be replace by regexp_replace with two regexp_substr function call grabbing what is before and after the space with the & character appended in between. Something like...
regexp_substr('SPACE MAN BEAR PIG DOG CAT','[^ ]+{4}',1,5) || ' % ' || regexp_substr('SPACE MAN BEAR PIG DOG CAT','[^ ]+',1,6)
I am trying to write a small pl/sql script and need some help.
first, I have 2 tables called project1 , project2. both tables have a column called cust_code.
cust_code values are varchar2 type. values always begin with 1. (number 1, decimal point) and 8 digits. for example 1.10002332
when I import data into project1 table, if the last digit is 0, for example 1.22321630, the last zero is dropped and then theres only seven digits beyond the decimal point. in that case it will be 1.2232163
the script I want to write will check whether there are only 7 digits beyond the decimal point and will insert that record into the project2 table.
this is what I came up with
DECLARE
CURSOR dif IS
SELECT CUST_CODE, CUST_ID, CONTRACT_NUM, MSISDN
FROM project1
WHERE CUST_CODE IN (SELECT CUST_CODE FROM CUST_ALL);
BEGIN
FOR a in dif LOOP
IF SUBSTR(a.CUST_CODE, 10)=null
THEN
INSERT INTO project2 (cust_code)
VALUES(a.CUST_CODE);
END IF;
END LOOP;
commit;
END;
the script runs with no errors but nothing happens. on the substr function, when I chose different value than NULL, then it works. I cant figure out how to check if the 8th digit is missing.
Assaf.
Your script doesn't work because of the line:
IF SUBSTR(a.CUST_CODE, 10)=null
In plsql <something> = null will always be FALSE.
You should write:
IF SUBSTR(a.CUST_CODE, 10) IS null
But actually you don't really nead plsql, you can do it with one sql command:
INSERT INTO project2 (cust_code)
SELECT CUST_CODE, CUST_ID, CONTRACT_NUM, MSISDN
FROM project1
WHERE CUST_CODE IN (SELECT CUST_CODE FROM CUST_ALL)
AND SUBSTR(a.CUST_CODE, 10) IS null;
Try this for your condition:
IF LENGTH(a.CUST_CODE) = 10 AND SUBSTR(a.CUST_CODE,-1,10) = '0'
(check if length is 10 and also last character is 0)
I have cust_nm column in a database. The column cust_nm is formatted with last name then first name are separated by a comma followed by a space than the middle initial.
TUNGESVIK, MARK M
I want to run a Oracle query to output this format.
If all your names are really in that exact format, you can do something like this
SQL> ed
Wrote file afiedt.buf
1 with x as (
2 select 'TUNGESVIK, MARK M' cust_nm from dual
3 )
4 select substr( cust_nm, 1, instr(cust_nm, ', ')-1 ) last_name,
5 substr( cust_nm, instr(cust_nm, ', ')+2, instr(cust_nm, ' ', -1) - instr(cust_nm, ', ')-2) first_name,
6 substr( cust_nm, instr(cust_nm, ' ', -1)+1, length(cust_nm) ) middle_initial
7* from x
SQL> /
LAST_NAME FIRS M
--------- ---- -
TUNGESVIK MARK M
When you start including people that don't have a middle initial (or that have multiple middle initials), people with multiple spaces in their last or first name, the probability that at least some names aren't in this format but some other format, things get a lot more challenging. There are software products whose only purpose is to take incoming name data, parse it, scrub it, and standardize it. Writing your own code to try to handle every corner case is likely to take way more time than you're expecting.