bach echo variable substitution - bash

I want make a query wiht this bash code.
##fist I will extrac the table name from table.txt file
table=$(head -n 1 tables.txt)
#In this code is where I will make the substitution on the query
result=`echo "select 'result '||segment_name||':'||MB||':'||TOTAL_MB from (
select TSEG.segment_name,round(TSEG.bytes/1024/1024) MB,l.segment_name as LSEGMENT_NAME,nvl(l.MB,0) as LOB_MB,nvl(l.MB,0)+round(TSEG.bytes/1024/1024) as TOTAL_MB
from dba_segments tseg, (select LOBS.table_name,round(bseg.bytes/1024/1024) MB,lobs.SEGMENT_NAME
from dba_lobs lobs,dba_segments bseg
where LOBS.SEGMENT_NAME=bseg.segment_name
order by bseg.bytes asc
) l
where TSEG.segment_type='TABLE'
and TSEG.segment_name='$table'
and TSEG.SEGMENT_NAME=l.table_name(+)
order by TOTAL_MB
)where rownum=1;`
my problem is on line TSEG.segment_name='$table', I need the table name on format 'TABLE_NAME'.
this is my actual ouput with table named "AABLG":
select 'result '||segment_name||':'||MB||':'||TOTAL_MB from (
select TSEG.segment_name,round(TSEG.bytes/1024/1024) MB,l.segment_name as LSEGMENT_NAME,nvl(l.MB,0) as LOB_MB,nvl(l.MB,0)+round(TSEG.bytes/1024/1024) as TOTAL_MB
from dba_segments tseg, (select LOBS.table_name,round(bseg.bytes/1024/1024) MB,lobs.SEGMENT_NAME
from dba_lobs lobs,dba_segments bseg
where LOBS.SEGMENT_NAME=bseg.segment_name
order by bseg.bytes asc
) l
where TSEG.segment_type='TABLE'
' and TSEG.segment_name='AABLG
and TSEG.SEGMENT_NAME=l.table_name(+)
order by TOTAL_MB
)where rownum=1;
you can see that the " ' " is on the first position, and I don't know why.
regards.
Marco.

This would be much better done without echo at all. Consider, for instance:
IFS=$'\r\n ' read -r table <tables.txt
IFS= read -r -d '' result <<EOF
select 'result '||segment_name||':'||MB||':'||TOTAL_MB from (
select TSEG.segment_name,round(TSEG.bytes/1024/1024) MB,l.segment_name as LSEGMENT_NAME,nvl(l.MB,0) as LOB_MB,nvl(l.MB,0)+round(TSEG.bytes/1024/1024) as TOTAL_MB
from dba_segments tseg, (select LOBS.table_name,round(bseg.bytes/1024/1024) MB,lobs.SEGMENT_NAME
from dba_lobs lobs,dba_segments bseg
where LOBS.SEGMENT_NAME=bseg.segment_name
order by bseg.bytes asc
) l
where TSEG.segment_type='TABLE'
and TSEG.segment_name='$table'
and TSEG.SEGMENT_NAME=l.table_name(+)
order by TOTAL_MB
) where rownum=1;
EOF
This also fixes the bug observed in your question by setting IFS to a value that includes $'\r', the carriage-return character found in DOS-formatted newlines, and thus stripping such characters when they exist at the end of the first line of tables.txt.

Related

How to add new line separator into data for oracle

I'm working on displaying data from oracle.
is there a way to make the following data inside the table:
example :
'1.somedata, 2.somedata, 3.somedata, 4.somedata, 5.somedata'
to display like:
example:
'1. somedata
2. somedata
3. somedata
4. somedata
5. somedata'
on the interface?
do i add new line separator directly into the data?
or do i separator them into new line when i query it?
or is there any other simple way?
Thanks.
There are so many ways to do this, here is one if you are selecting from a column:
SELECT REPLACE ('1.somedata, 2.somedata, 3.somedata, 4.somedata, 5.somedata', ',', CHR (13) || CHR (10)) AS split
FROM DUAL;
1.somedata
2.somedata
3.somedata
4.somedata
5.somedata
I personally would use the listagg function and use '' as the delimiter.
SELECT LISTAGG(last_name, ' ')
WITHIN GROUP (ORDER BY hire_date, last_name) "Emp_list",
MIN(hire_date) "Earliest"
FROM employees
WHERE department_id = 30;
Remember that Apex is generating a web page, which means the end result is HTML. Apex, however, will also sometimes escape special HTML characters for you, like < and &. Since you're viewing a table, I assume the source of your data is a query and your "somedata" field is a single column. Try this:
SELECT REPLACE( somedata_column, ',', '<br />' )
FROM mytable
You don't say what version of Apex. In Apex 4.x, the column would need to be set to a Standard Report Column, which would stop Apex from the <br> elements. I forget what the column type is in Apex 5.x.
Check below sample query which converts coma separated list data into rows
SELECT substr( '1.AL,2.AL,3.AL,4.AL,5.AL,6.AL,',
( case when rownum = 1 then 1
else instr( '1.AL,2.AL,3.AL,4.AL,5.AL,6.AL,', ',', 1, rownum - 1 ) + 1
end ),
instr( substr( '1.AL,2.AL,3.AL,4.AL,5.AL,6.AL,',
( case when rownum = 1 then 1
else instr( '1.AL,2.AL,3.AL,4.AL,5.AL,6.AL,', ',', 1, rownum - 1 ) + 1
end )
), ',' ) - 1
) as data
FROM dual
CONNECT BY LEVEL <= length( '1.AL,2.AL,3.AL,4.AL,5.AL,6.AL,' ) - length ( replace('1.AL,2.AL,3.AL,4.AL,5.AL,6.AL,', ',') )
Hope this will help you!

Processing multi line logs with AWK to gather SQL statements

I have the following entries in a log file:
2016-01-25 21:12:41 UTC:172.31.21.125(56665):user#production:[21439]:ERROR: bind message supplies 1 parameters, but
prepared statement "" requires 0
2016-01-25 21:12:41 UTC:172.31.21.125(56665):user#production:[21439]:STATEMENT: SELECT count(*) AS total FROM (
SELECT 1 AS count
FROM leads_search_criteria_entities
INNER JOIN entities e on entity_id = e.viq_id
LEFT JOIN companies_user cu ON cu.entity_id = e.viq_id
WHERE criterium_id = 644 AND ((
( cu.udef_type IS NULL -- if not set by user, check calculated value
AND is_university >= 50
) OR (
cu.udef_type IS NOT NULL -- if set by user, use it
AND cu.udef_type = 'university'
)
))
GROUP BY e.viq_id
ORDER BY e.viq_id
) x
2016-01-25 21:14:11 UTC::#:[2782]:LOG: checkpoint starting: time
2016-01-25 21:14:16 UTC::#:[2782]:LOG: checkpoint complete: wrote 51 buffers (0.0%); 0 transaction log file(s) added, 0 remov
ed, 0 recycled; write=5.046 s, sync=0.038 s, total=5.091 s; sync files=18, longest=0.008 s, average=0.002 s
2016-01-25 21:19:11 UTC::#:[2782]:LOG: checkpoint starting: time
I would like to capture the SQL statements but I am not sure how can I do that with AWK.
Update:
Expected outcome:
SELECT count(*) AS total FROM ( SELECT 1 AS count FROM leads_search_criteria_entities INNER JOIN entities e on entity_id = e.viq_id LEFT JOIN companies_user cu ON cu.entity_id = e.viq_id WHERE criterium_id = 644 AND (( ( cu.udef_type IS NULL -- if not set by user, check calculated value AND is_university >= 50 ) OR ( cu.udef_type IS NOT NULL -- if set by user, use it AND cu.udef_type = 'university' ) )) GROUP BY e.viq_id ORDER BY e.viq_id ) x
My current almost working solution uses sed but this is where I got stuck, it just helps filtering the lines that have a select (multiple lines by itself) and the next line after that. Any suggestion is appreciated
sed -n "/:STATEMENT:/,/2016/p" out
I don't recommend using sed for this. First thought for an awk solution might look like this:
/^2016/&&line~/:STATEMENT:/ {
sub(/.*:STATEMENT:/,"",line)
print line
}
/^2016/ {
line=""
}
{
$1=$1
line=sprintf("%s %s",line,$0)
}
END {
if (line~/:STATEMENT:/) {
sub(/.*:STATEMENT:/,"",line)
print line
}
}
Obviously you could shrink this. I wrote and ran it (for testing) as a one-liner.
The idea here is that:
we'll append to a variable, resetting it every time our input line starts with the year. (You could replace this with a regexp matching the date if you want to run this next year without modification),
when we get to a new log line (or the end), we strip off the cruft before the SQL statement and print the result.
Note the $1=$1. The purpose of this is to change your line's whitespace, so that newlines and tabs and multiples spaces are collapsed into single spaces. Experiment with removing it to see the impact.
Update
Howabout a combination of sed and tr
sed 's/^[0-9][^S]*//' INPUT.txt | sed '/^[0-9a-z]/d' | tr -s ' ' | tr -d '\n'
output:
STATEMENT: SELECT count(*) AS total FROM ( SELECT 1 AS count FROM leads_search_criteria_entities INNER JOIN entities e on entity_id = e.viq_id LEFT JOIN companies_user cu ON cu.entity_id = e.viq_id WHERE criterium_id = 644 AND (( ( cu.udef_type IS NULL -- if not set by user, check calculated value AND is_university >= 50 ) OR ( cu.udef_type IS NOT NULL -- if set by user, use it AND cu.udef_type = 'university' ) )) GROUP BY e.viq_id ORDER BY e.viq_id ) x
$ cat log.awk
f && /^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/ {f=0; print ""}
sub(/^.*:STATEMENT:[[:space:]]+/,"") {f=1}
f { $1=$1; printf "%s ", $0 }
$ awk -f log.awk log.txt
SELECT count(*) AS total FROM ( SELECT 1 AS count FROM leads_search_criteria_entities INNER JOIN entities e on entity_id = e.viq_id LEFT JOIN companies_user cu ON cu.entity_id = e.viq_id WHERE criterium_id = 644 AND (( ( cu.udef_type IS NULL -- if not set by user, check calculated value AND is_university >= 50 ) OR ( cu.udef_type IS NOT NULL -- if set by user, use it AND cu.udef_type = 'university' ) )) GROUP BY e.viq_id ORDER BY e.viq_id ) x
(2nd line) This turns on printing (f=1) when :STATEMENT: is found, and as a side-effect, removes everything up until the start of the SELECT statement.
(3rd line) Then it keeps printing until printing is turned off (see below), cleaning up by replacing sequences of multiple spaces by a single space. (EDIT: Thanks to #ghoti for suggesting the elegant $1=$1 for that.)
(1st line) Turn off printing at the start of the next log, identified by starting with a date. Print a courtesy newline to end the SELECT.

SP2-0042: unknown command "ENDD" - rest of line ignored

I have script which is calling sqlplus to perform an operation. But, the sqlplus is returning this error always once the script is executed.
unknown command "ENDD" - rest of line ignored.
Here is my sql written inside the script :
map=sqlplus -s <<ENDD
$db_connection_string
SET BLANKLINES ON
SET VERIFY OFF HEADING OFF ECHO OFF FEEDBACK OFF
ALTER SESSION SET CURRENT_SCHEMA=$MY_DB;
select
TRIM(( select Col1 from tableA where tableB.col2=col2 and col3 = 100)) ||'#' ||
TRIM(tableB.col3 )||'#'||
tableB.col4 ||'#'||
tableB.col5 ||'#'||
tableB.col6 ||'#'||
TRIM(( select tableC.col1 from tableC WHERE tableC.col2=10050 AND tableC.col4 = 1 and tableC.col3 = tableB.col4)) AS ACT#TNID#INS#DC#CHNL#EXTSYSIDK
from tableB
where
tableB.col3='$evn'
and rownum <2;
ENDD
You're missing the command substitution syntax:
map=$(sqlplus -s <<ENDD
...
ENDD
)

Oracle SQL substr/instr solution required

I need help with an SQL statement I am trying to run, I have done quite a bit of reading and testing but I cannot get the correct results hence my request here.
I am trying to extract data from a column that has had data concatenated from two sources, I want to seperate the data before & after the join, the join is a ' - ' (hyphen with a space either side), there can be alphanumeric chars before or after that ' - ' and this is the data I need. Just to add to the complexity some rows do not have joined data, i.e. there is no ' - ' and when this is met it is ok to simply extract the whole column value and treat it as the BB side (see first BB example below).
So when I have finished I would like to have seperated out the AA side (before the -) and the BB side (after the -) allowing for the single BB situation.
Looking at the data the following scenarious can occur.
BB<br>
AA - BB<br>
AA-aa - BB<br>
AA - BB-bb-cc<br>
AA-aa - BB-bb-cc<br>
I can get code to work but not consistently for all of the above scenarious - can you suggest the right code or even if there is a better solution which does not impact SQL performance.
Examples I have been trying for AA side:-
WORKS:
select substr('AA - BB-bb', 0, instr('AA - BB-bb', ' - ', 1, 1)-1) AS A_NAME
from DUAL;
FAILS (Only gets AA, not AA-aa):
select substr('AA-aa - BB-bb', 0,instr('AA-aa - BB-bb', ' - ', 1, 1)-1) AS A_NAME
from DUAL;
Examples I have been trying for BB side:-
FAILS:
select SUBSTR('AA-aa - WHENEHEH', INSTR('AA-aa - WHENEHEH',' - ', -1, 1)+1, 100)
B_NAME from dual;
thanks, Mark.
If your seperator is sure gona be a "space on either side of a hypen"
Then you can use CHR() function.
From your try
select substr('AA-aa - BB-bb', 0,instr('AA-aa - BB-bb', ' - ', 1, 1)-1) AS A_NAME
from DUAL;
Use something like this
select substr('AA-aa - BB-bb',0,instr('AA-aa - BB-bb',chr(32))-1) from dual; /* ASCII value for space is chr(32) /*
O/P
AA-aa
select substr('AA-aa - BB-bb',instr('AA-aa - BB-bb',chr(32))+2,10) from dual;
O/P
" - BB"
Assuming that, as shown in your list of scenarios, the pattern '- BB' can be relied on, you can use that to find the split.
WITH
DATA AS (
SELECT 'BB' text FROM dual
UNION ALL SELECT 'AA - BB' FROM dual
UNION ALL SELECT 'AA-aa - BB' FROM dual
UNION ALL SELECT 'AA - BB-bb-cc' FROM dual
UNION ALL SELECT 'AA-aa - BB-bb-cc' FROM dual
),
break AS (
SELECT text, instr(text, '- BB') breakpos FROM DATA
)
SELECT
text,
CASE WHEN breakpos = 0 THEN NULL ELSE substr( text, 1, breakpos-1 ) END aa_side,
case when breakpos = 0 then text else substr( text, breakpos+2) end bb_side
FROM break
;
Here is something that I think will work for you. (I hope I understood your requirement right)
I tried the query with all the examples you had mentioned and it works good.
SELECT REGEXP_SUBSTR ('AA-aa - BB-bb-cc',
'[^ - ]+')
"Right Side",
SUBSTR ('AA-aa - BB-bb-cc',
INSTR ('AA-aa - BB-bb-cc',
' - ')
+ 2)
"Left Side"
FROM DUAL;
This one works for everything but for BB and as a work around for that you can check if the delimiter exist and if it doesn't you can take the entire value for the right side.
SELECT SUBSTR ('AA aa - BB',0,
INSTR ('AA aa - BB',
' - ')
)
"Right Side",
SUBSTR('AA aa - BB',INSTR('AA aa - BB',
' - ')+2)
"Left Side"
FROM DUAL;
Your condition of a single value show up in second column instead of first is a bit odd, but this should do everything else you require:
with testdata as (
select 'BB' as input_col, 1 as row_num from dual
union
select 'AA - BB', 2 from dual
union
select 'AA-aa - BB',3 from dual
)
select testdata.row_num,
case when (regexp_instr(testdata.input_col,'(\ -\ )') > 0) then
regexp_replace(testdata.input_col, '(.*)(\ -\ )(.*)$', '\1')
else null
end output_col1,
regexp_replace(testdata.input_col, '(.*)(\ -\ )(.*)$', '\3') as output_col2
from testdata
order by testdata.row_num;
Edit: I modified the above to add the case check. I admit there is probably a more eloquent way to do this via the regexp_replace itself, but this works too.

How do I display a field's hidden characters in the result of a query in Oracle?

I have two rows that have a varchar column that are different according to a Java .equals(). I can't easily change or debug the Java code that's running against this particular database but I do have access to do queries directly against the database using SQLDeveloper. The fields look the same to me (they are street addresses with two lines separated by some new line or carriage feed/new line combo).
Is there a way to see all of the hidden characters as the result of a query?I'd like to avoid having to use the ascii() function with substr() on each of the rows to figure out which hidden character is different.
I'd also accept some query that shows me which character is the first difference between the two fields.
Try
select dump(column_name) from table
More information is in the documentation.
As for finding the position where the character differs, this might give you an idea:
create table tq84_compare (
id number,
col varchar2(20)
);
insert into tq84_compare values (1, 'hello world');
insert into tq84_compare values (2, 'hello' || chr(9) || 'world');
with c as (
select
(select col from tq84_compare where id = 1) col1,
(select col from tq84_compare where id = 2) col2
from
dual
),
l as (
select
level l from dual
start with 1=1
connect by level < (select length(c.col1) from c)
)
select
max(l.l) + 1position
from c,l
where substr(c.col1,1,l.l) = substr(c.col2,1,l.l);
SELECT DUMP('€ÁÑ', 1016)
FROM DUAL
... will print something like:
Typ=96 Len=3 CharacterSet=WE8MSWIN1252: 80,c1,d1

Resources