As my title, somecases I see Regexp_substr faster and less cost than Instr and somecases its opposite.
I don't know when I should use Instr or Regexp_substr, someone can explain for me and tell me benefit of each? The example following:
**Regexp_substr:**
SELECT * FROM tabl1
WHERE 1 = 1
AND col1 IN (
SELECT regexp_substr(abc,'[^,]+',1,level) AS A
FROM (
SELECT 001 abc -- replace with parameter
FROM DUAL
)
CONNECT BY LEVEL <= LENGTH (REGEXP_REPLACE (abc,'[^,]'))+1 );
**Instr:**
SELECT * FROM tabl1
WHERE 1 = 1
AND INSTR (',' || '001' || ',',',' || col1 || ',') > 0 ;
Thanks!
I have following sql query in code, which is makes query go slow:
SELECT a.*,
(SELECT CASE
WHEN (score IS NOT NULL OR comments IS NOT NULL)
THEN
' ( score : ' || TO_CHAR (SCORE) || ' )'
ELSE
' ( hələ )'
END
FROM t_lecture_task_present b
WHERE b.t_idx = a.t_idx AND B.STUDENT_ID = '{$member_code}')
AS task_score
FROM t_lecture_task a
WHERE a.lec_open_idx = '24422'
ORDER BY s_date ASC, t_idx ASC
(16 seconds)
If I try query without
(SELECT CASE
WHEN (score IS NOT NULL OR comments IS NOT NULL)
THEN
' ( score : ' || TO_CHAR (SCORE) || ' )'
ELSE
' ( hələ )'
END
FROM t_lecture_task_present b
WHERE b.t_idx = a.t_idx AND B.STUDENT_ID = '{$member_code}')
as task_score
it works faster.
So, I tried removing or comments is not null, and it works got 2 seconds faster.
You can't compare the performance of queries that produce different results :)
Depending on data distribution in your tables, you would likely benefit from these indexes:
t_lecture_task(lec_open_idx)
t_lecture_task_present(t_idx, student_id)
Try to re-write your query to use joins instead of scalar sub queries (select as a column). Not only are they more awkward to read, they are more difficult to optimize.
select a.*
,case when score is not null
or comments is not null then ' ( score : ' || to_char (score) || ' )'
else ' ( hələ )'
end as task_score
from t_lecture_task a
left join t_lecture_task_present b on(
b.t_idx = a.t_idx
and b.student_id = '{$member_code}')
)
where a.lec_open_idx = '24422';
How do I assign a value to a variable using a select statement and use it in a SQL*Plus script, something like this?
VARIABLE FullCatCode VARCHAR2(7)
exec :FullCatCode := (SELECT CatCode from draw_catcodes where series = 123 and base = 158);
SELECT :FullCatCode || '-' || Other stuff... from table_name...
EDIT: #AlexPoole, Sorry for the imprecise problem statement. I am extracting 50 columns of data from a 280K record dataset. I am assigning sequence nextval's to each record based on a substring from a secondary table (draw_catcodes). I am running the SELECT statement in SQL*Plus, spooling to a CSV file. The SQL now looks like this (testing your second recommendation below):
COLUMN CatCode NEW_VALUE FullCatCode;
SELECT
(CASE d.image WHEN 0 THEN 'NoImage.pdf'
ELSE lower(d.prefix || lpad(d.series,3,0) || lpad(d.base,3,0) || lpad(d.suffix,2,0) || lpad(d.rev,2,0) || '.pdf') END) as "Filename",
(SELECT EngDiscipline from draw_catcodes c where d.series = c.series and d.base = c.base) as "EngDiscipline",
(SELECT CatCode from draw_catcodes c where d.series = c.series and d.base = c.base),
SELECT &FullCatCode || '-' ||
lpad((CASE substr(&FullCatCode,0,3)
WHEN 'AEG' THEN (SELECT AEG_seq.NEXTVAL FROM DUAL)
WHEN 'ARY' THEN (SELECT ARY_seq.NEXTVAL FROM DUAL)
WHEN 'BBR' THEN (SELECT BBR_seq.NEXTVAL FROM DUAL)
ELSE 0
END),6,0) as "ItemID",
upper(d.prefix || '-' || lpad(d.series,3,0) || '-' || lpad(d.base,3,0) || '-' || lpad(d.suffix,2,0)) as "LegacyID",
...
from tablename where ...
I started with a Stored Function that 'Upserted' a table of sequences (can't perform DML from a Function), tried a Stored Procedure with an OUT variable (couldn't call the procedure from within the SQL SELECT), now trying sequences in a CASE statement (can't figure out how to use variables as described above)... Any suggestions would be much appreciated!
EDIT: #AlexPoole, Since the variables won't work in this context, I just SELECT the value I'm after directly, then use a CASE statement to specify the proper sequence. The syntax is not right though, as I am getting an ORA-00933: SQL command not properly ended error on the next line:
SELECT ((SELECT CatCode from draw_catcodes c where d.series = c.series and d.base = c.base) || '-' ||
lpad((CASE substr((SELECT CatCode from draw_catcodes c where d.series = c.series and d.base = c.base),0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
...
WHEN 'SPR' THEN SPR_seq.NEXTVAL
WHEN 'SRL' THEN SRL_seq.NEXTVAL
ELSE 0
END),6,0)) as "ItemID" FROM DUAL,
upper(d.prefix || '-' || lpad(d.series,3,0) || '-' || lpad(d.base,3,0) || '-' || lpad(d.suffix,2,0)) as "LegacyID",
EDIT: #AlexPoole, I added the JOIN and cleaned up the SELECT but now get an ORA-02287: sequence number not allowed here
(c.CatCode || '-' ||
(SELECT lpad(
(CASE substr(c.CatCode,0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
WHEN 'BSY' THEN BSY_seq.NEXTVAL
...
WHEN 'SDR' THEN SDR_seq.NEXTVAL
WHEN 'SLC' THEN SLC_seq.NEXTVAL
WHEN 'SLD' THEN SLD_seq.NEXTVAL
WHEN 'SMS' THEN SMS_seq.NEXTVAL
WHEN 'SPP' THEN SPP_seq.NEXTVAL
WHEN 'SPR' THEN SPR_seq.NEXTVAL
WHEN 'SRL' THEN SRL_seq.NEXTVAL
ELSE 0 END ),6,0) FROM DUAL)) as "ItemID",
...
FROM md_draw d
join draw_catcodes c on d.series = c.series and d.base = c.base
order by lpad(d.series,3,0), lpad(d.base,3,0), lpad(d.suffix,2,0);
Any suggestions?
EDIT: #AlexPoole, You're right, I removed the subquery containing the sequence call as you detailed it, but still get the ORA-02287: sequence number not allowed here error:
SELECT
(CASE d.image WHEN 0 THEN 'NoImage.pdf'
ELSE lower(d.prefix || lpad(d.series,3,0) || lpad(d.base,3,0) || lpad(d.suffix,2,0) || lpad(d.rev,2,0) || '.pdf') END) as "Filename",
c.EngDiscipline as "EngDiscipline",
c.CatCode || '-' || lpad(CASE substr(c.CatCode,0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
...
WHEN 'SPP' THEN SPP_seq.NEXTVAL
WHEN 'SPR' THEN SPR_seq.NEXTVAL
WHEN 'SRL' THEN SRL_seq.NEXTVAL
ELSE 0 END,6,'0') as "ItemID",
upper(d.prefix || '-' || lpad(d.series,3,0) || '-' || lpad(d.base,3,0) || '-' || lpad(d.suffix,2,0)) as "LegacyID",
...
FROM md_draw SAMPLE (1) d
join draw_catcodes c on d.series = c.series and d.base = c.base
order by c.ccProgram, lpad(d.series,3,0), lpad(d.base,3,0), lpad(d.suffix,2,0);
It is fairly easy. In PL/SQL a query either needs to be a cursor, or you have to select into something; in this, into your bind variable:
VARIABLE FullCatCode VARCHAR2(7)
exec SELECT CatCode into :FullCatCode from draw_catcodes where series = 123 and base = 158;
SELECT :FullCatCode || '-' || Other stuff... from table_name...
If you're only going to use it in later SQL statements you could also use a substitution variable, instead of a bind variable:
COLUMN CatCode NEW_VALUE FullCatCode
SELECT CatCode from draw_catcodes where series = 123 and base = 158;
SELECT &FullCatCode || '-' || Other stuff... from table_name...
With your modified question, this isn't what you're trying to do at all. You're trying to refer to a value from a subquery in another part of the same query, not a separate statement later in your script. And there is no PL/SQL involved.
You can't do that with either mechanism above; the first because there is no PL/SQL block to do the select ... into, and the second because substitution variables are evaluated and replaced before the statement is run - the new_value doesn't exist until after the query has run.
You don't want a subquery here though, you should be using a join, something like:
SELECT
CASE d.image WHEN 0 THEN 'NoImage.pdf'
ELSE lower(d.prefix || lpad(d.series,3,'0') || lpad(d.base,3,'0') || lpad(d.suffix,2,'0') || lpad(d.rev,2,'0') || '.pdf')
END as "Filename",
c.EngDiscipline as "EngDiscipline",
c.CatCode, -- not sure if you actually want this raw value?
c.CatCode || '-' || lpad(CASE substr(c.CatCode,0,3)
WHEN 'AEG' THEN AEG_seq.NEXTVAL
WHEN 'ARY' THEN ARY_seq.NEXTVAL
WHEN 'BBR' THEN BBR_seq.NEXTVAL
ELSE 0
END,6,'0') as "ItemID",
upper(d.prefix || '-' || lpad(d.series,3,'0') || '-' || lpad(d.base,3,'0') || '-' || lpad(d.suffix,2,'0'))
as "LegacyID",
...
from tablename d
join draw_catcodes c on d.series = c.series and d.base = c.base
where ...
You can refer directly to c.CatCode in the places you were trying to use &FullCatCode.
If the sequences only exist for this query and the ItemId has no wider significance, you could use an analytic function to generate the ItemIds instead:
c.CatCode || '-' ||
lpad(row_number() over (partition by substr(c.CatCode,0,3) order by null),6,'0')
as "ItemID",
There will be no deterministic ordering of the ItemIds, but there wouldn't be with the sequence approach; and with this you could modify the windowing clause to specify the ordering if that was desirable.
I have this sql:
with p_1 as
(
select 1 sorszam, 'X1' tipus from dual
union all select 2 sorszam, 'X2' tipus from dual
union all select 3 sorszam, 'X3' tipus from dual
)
select (
(case when p1.sorszam=1 then ('[' || chr(13) || chr(10)) else '' end) ||
p1.tipus
|| (case when p1.sorszam=(select max(sorszam) from p_1) then (chr(13) || chr(10) || ']') else '' end)
) szoveg
from p_1 p1
order by p1.sorszam
The result is:
SZOVEG
--------
[
X1
X2
X3
]
My question is: why is there a blank line after the first line?
Using SET RECSEP OFF removes the record separator.
http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12040.htm#i2699269
I have three columns in a tables
Column names with datatypes
First_week - Number
Days - Number
Second_week- Number
Column Values
8
6
11
I want to concatenate these values such that result returns 8/6/11
If anyone of the column values are null then the concatenation must be 8/-/11
If all are null then the result must be -/-/-
How can this be achieved in an oracle query?
To achieve that you could use decode, nvl functions or case expression. Here is an example of using decode:
with your_table(First_week, Days, Second_week) as(
select 8, 6, 11 from dual union all
select 5, null, 12 from dual union all
select null, 7, null from dual union all
select null, null, null from dual
)
select decode(to_char(First_week), null, '-', to_char(First_week)) || '/' ||
decode(to_char(Days), null, '-', to_char(Days)) || '/' ||
decode(to_char(Second_week), null, '-', to_char(Second_week)) as result
from your_table
RESULT
---------
8/6/11
5/-/12
-/7/-
-/-/-
http://www.techonthenet.com/oracle/functions/coalesce.php
"In Oracle/PLSQL, the coalesce function returns the first non-null expression in the list. If all expressions evaluate to null, then the coalesce function will return null."
http://docs.oracle.com/cd/B19306_01/server.102/b14200/operators003.htm#i997789
"|| Concatenates character strings and CLOB data."
Now we have all the building blocks to write something like:
COALESCE(First_week, '-') || '/' || COALESCE(Days, '-') || '/' || COALESCE(Second_week, '-')
What About This
SELECT NVL (TO_CHAR (FIRST_WEEK), '-')
|| '/'
|| NVL (TO_CHAR (DAYS), '-')
|| '/'
|| NVL (TO_CHAR (SECOND_WEEK), '-')
FROM YOUR_TABLE