How to use apex_string.split? - oracle

I'm trying to split a string : OK#15#78 by #
I would like to get the first part of the string : Ok
I tried the following queries but it's not working :
select apex_string.split('OK#15#78','#')[0] from dual;
Can anyone help please ?
Cheers

You could use TABLE and rownum:
SELECT val
FROM (Select rownum AS rn, column_value AS val
FROM TABLE(apex_string.split('OK#15#78','#')))
WHERE rn = 1;

ORIGNAL POST:
Even simpler:
SELECT COLUMN_VALUE val, ROWNUM
FROM apex_string.split('OK#15#78','#')
WHERE ROWNUM = 1;
Or maybe even faster:
SELECT COLUMN_VALUE val
FROM apex_string.split('OK#15#78','#')
FETCH FIRST 1 ROWS ONLY
REVISED ANSWER
There is a caveat here: APEX_STRING.SPLIT results in a nested table, and there are no guarantees about the order of the returned items, so this actually doesn't work.
You should use the regxp_substr method
SELECT val c
FROM
(
(SELECT regexp_substr('OK#15#78','[^#]+', 1, level)
FROM DUAL
CONNECT BY regexp_substr(, '[^#]+', 1, level) IS NOT NULL)
)
FETCH FIRST 1 ROWS ONLY

Related

How to pass parameter from query to subquery ? ORA-00904

I get ORA-00904 invalid identifier error, from this query
SELECT
tab1."col1" AS ID,
tab1."col4" AS Name,
tab1."col5" AS Place,
(SELECT SUBSTR (SYS_CONNECT_BY_PATH (one_row , ';'), 2) myConString
FROM (SELECT tab2."col3" || ',' || tab2."col4" AS one_row,
ROW_NUMBER () OVER(ORDER BY tab2."col1") rn,
COUNT (*) OVER () cnt
FROM dbo."table2" tab2
WHERE tab2."col1" = tab1."col1"
AND tab2."col2" = tab1."col2")
WHERE rn = cnt
START WITH rn = 1
CONNECT BY rn = PRIOR rn + 1)
FROM dbo."table1" tab1
WHERE tab1."col1" IN (1,2,3)
AND tab1."col2" = 1 AND tab1."col3" = 1;
in this specific place
tab2."col1" = tab1."col1" AND tab2."col2" = tab1."col2"
In the subquery I concatenate rows into string and it works great and give me the right results, something like
1,100;1,200;2,150....
I think problem is that I try to refer to objects more then one level of subquery, but I can't figure it out, how to rewrite the query.
Thanks for any help
Correlated subqueries can only reference things one level deep. Your tab1 table is two levels away from your tab2 table.
I can't quite wrap my head around your query, but can you rewrite this so that you have a join between tab1 and tab2 instead of having a correlated query in the select clause?

Not a single-group group function on a case count in oracle

I'm trying to adapt a query that works in MSSQL to Oracle, the query is much bigger (this part is just a field from a much bigger query) but I managed to reduce it so it looks simpler.
SELECT CASE WHEN COUNT(*) > 0 THEN COUNT(*)
ELSE (SELECT COUNT(*) FROM table2)
END
FROM table1
The error I'm getting is:
ora-00937 not a single-group group function
Can someone tell me where's the problem or how can I redefine it?
You can try with this query:
SELECT CASE WHEN (SELECT COUNT(*) FROM table1) > 0 then (SELECT COUNT(*) FROM table1)
ELSE (SELECT COUNT(*) FROM table2)
END
FROM dual;
It is still ugly but it works :)
Update:
To explain how it's working:
We have 2 cases:
If there are records in the table1 then show me how many records
there are
If the table1 is empty, then give me the number of records from the
table2
Dual is the dummy table.
I think that NikNik answer is cleaner but another solution would be:
SELECT *
FROM (SELECT CASE
WHEN Count(*) > 0 THEN Count(*)
ELSE (SELECT Count(*)
FROM table2)
END
FROM table1
GROUP BY table1.primarykey1,
table1.primarykey2)
WHERE ROWNUM = 1

Oracle Loop delimited list to check if record exist

I'm new in PL/SQL, and Got a code from an old program that check if a record exist in a table something like :
oRetValue := ' ';
SELECT f1
INTO oRetValue
FROM t1
WHERE w1='w1'
AND code = iCode;
it was ok before, but now the application has more than 500 rows to verify. I'd like to pass a string with all the code separated by comma, and the procedure will loop and return all icode not found. Any help would be greatly appreciated.
Try this:
select f1
into oretvalue
from t1
where w1 = 'w1'
and code in
(select p_code
from (select level as id,
regexp_substr(icode, '[^,]+', 1, level) as p_code
from dual
connect by regexp_substr(icode, '[^,]+', 1, level) is not null));

Exists query with not equal running extremly slow

I am trying to modify a query that someone else wrote which is taking a really long time to run. The problem has to do with the <> portion of the exists query. Any idea how this can be changed to run quicker?
SELECT m.level4 center, cc.description, m.employeename, m.empno,
TO_DATE (ct.tsdate, 'dd-mon-yyyy') tsdate, ct.starttime, ct.endtime,
ct.DURATION,
NVL (DECODE (ct.paycode, ' ', 'REG', ct.paycode), 'REG') paycode,
ct.titlecode, ct.costcenter, m.tsgroup
FROM clairvia_text ct, MASTER m, costcenteroutbound cc
WHERE ct.recordtype = '1'
AND ct.empno = m.empno
AND m.level4 = cc.center
AND EXISTS (
SELECT ct1.recordtype,ct1.empno,ct1.tsdate,ct1.processdate
FROM clairvia_text ct1
WHERE ct.recordtype = ct1.recordtype
AND ct.empno = ct1.empno
AND ct.tsdate = ct1.tsdate
AND ct.processdate = ct1.processdate
group by ct1.recordtype,ct1.empno,ct1.tsdate,ct1.processdate
having count(*) < 2)
Oracle can be finnicky with exists statements and subqueries. A couple of things to try:
Change the exists to an "in"
Change the exists to a group by statement with a "having count(1) > 1". This could even be changed into a join.
I'm assuming indexes are not an issue.
You can use analytic function count here to eliminate duplicated rows.
select * from (
SELECT m.level4 center, cc.description, m.employeename, m.empno,
TO_DATE (ct.tsdate, 'dd-mon-yyyy') tsdate, ct.starttime, ct.endtime,
ct.DURATION,
NVL (DECODE (ct.paycode, ' ', 'REG', ct.paycode), 'REG') paycode,
ct.titlecode, ct.costcenter, m.tsgroup,
count(1) over (partition by ct.recordtype,ct.empno,ct.tsdate,ct.processdate
order by null) cnt
FROM clairvia_text ct, MASTER m, costcenteroutbound cc
WHERE ct.recordtype = '1'
AND ct.empno = m.empno
AND m.level4 = cc.center
) where cnt=1
I do not have your structures and data, so I run similar queries with all_tab_cols and first query took ~500s on my laptop and second query ~2s.
-- slow test
select count(1)
from all_tab_cols atc
where exists (
select 1
from all_tab_cols atc1
where atc1.column_name = atc.column_name
group by column_name
having count(1) = 1)
-- fast test
select count(1)
from (
select column_name,
count(1) over (partition by atc.column_name order by null) cnt
from all_tab_cols atc
)
where cnt = 1

No Results returned for ROW_NUMBER() query

I am getting "no results returned" for the following query:
SELECT
Referer
FROM
(SELECT
ROW_NUMBER() OVER (ORDER BY CT.Referer ASC) AS RowNum,
CT.Referer, CT.LastModified
FROM
ClickTrack CT
JOIN
OrderTrack OT ON OT.ClickTrackID = CT.ClickTrackID
GROUP BY
CT.Referer, CT.LastModified
HAVING
LEN(CT.Referer) > 0) as num
WHERE
RowNum = 1
AND LastModified BETWEEN '07/06/2013' and '08/05/2013'
Curiously, when I leave off RowNum = 1, I get the full list of values. I need to get one at a time though to assign to a variable and drop into a temporary table.
The end query will be in a while loop using scalar variables in place of the date ranges and RowNum comparison.
Any help is appreciated. Thank you!
I'm thinking RowNum 1 may not have a date between your selections. Maybe put the date selection inside so that you know that the first one matches.
SELECT Referer
FROM (SELECT ROW_NUMBER() OVER (ORDER BY CT.Referer ASC)
AS RowNum, CT.Referer, CT.LastModified
FROM ClickTrack CT
JOIN OrderTrack OT ON OT.ClickTrackID = CT.ClickTrackID
WHERE CT.LastModified BETWEEN '07/06/2013' and '08/05/2013'
GROUP BY CT.Referer, CT.LastModified
HAVING LEN(CT.Referer) > 0) as num
WHERE RowNum = 1

Resources