Bash Heredoc format adding a new line at the end of ); - bash

I'm trying to create a bash script to create automated sql statements to run them in DB without the effort of manually modify the .sql script and avoid human error, there is an issue when it generates the output files using heredoc format, is adding a new line at the end of the bash script where sql statement end in );
I know this can be easy thing like scape this characters but I tried to scape them with backslash and is not working, here is my example:
cat <<EOF >> $updateTabletmp
INSERT INTO ${table}_${currentTimeStamp}
SELECT * FROM ${table} WHERE field_1= ${count} AND field_2 = (SELECT field_2
FROM bartable WHERE field_2 = ${store});
EOF
This is the current output:
INSERT INTO foo_123419294
SELECT * FROM PHYPIOEE WHERE field_1 = 2177 AND field_2= (SELECT field_2
FROM bartable WHERE field_2 = 8788
);
As you can see of some reason ); is moved as a new line, the expected output will be something like this:
INSERT INTO foo_123419294
SELECT * FROM PHYPIOEE WHERE field_1 = 2177 AND field_2= (SELECT field_2
FROM bartable WHERE field_2 = 8788);
Thanks

Just tested your script and it does not add any unexpected new line/s
#!/bin/sh
out=out.txt
table=table
currentTimeStamp=12345678
count=123
store=asdf
cat <<EOF >> $out
INSERT INTO ${table}_${currentTimeStamp}
SELECT * FROM ${table} WHERE field_1= ${count} AND field_2 = (SELECT field_2
FROM bartable WHERE field_2 = ${store});
EOF
and the result is:
INSERT INTO table_12345678
SELECT * FROM table WHERE field_1= 123 AND field_2 = (SELECT field_2
FROM bartable WHERE field_2 = asdf);
So the reason can be only one: your ${store} variable contains new line.
And that's the answer.

Related

unix: compare two tables with unique_id of both table match

I have 2 tables where both table's unique_id will match. Comparison of both tables will produce highlighted mismatches of data in each column with basis of the unique_id. Sample as below;
Table A:
enter image description here
Table B:
enter image description here
Result:
enter image description here
Unique_id should play an important role here. If no unique_id matched present, results should throw null/empty records.
Any idea of how i can solve this?
file: t1.csv
maria;22;us
bryon;23;uk
alex;24;aus
file: t2.csv
maria;22;us
bryon;24;uk
alex;24;aus
file: test.sh
#!/bin/sh
sqlite3 <<EOF
create table t1 (id,a,b);
create table t2 (id,a,b);
.separator ;
.import $1 t1
.import $2 t2
select t1.*,' <-> ', t2.*
from t1
left join t2 on t1.id = t2.id
where t1.a <> t2.a
or t1.b <> t2.b
or t2.id is null;
EOF
how to use:
$ bash test.sh t1.csv t2.csv
bryon;23;uk; <-> ;bryon;24;uk
but also check for empty rows in t1.csv
$ bash test.sh t2.csv t1.csv

How to use not exists with insert?

I'm trying to frame the below query but it always gives me the error "SQL command not properly ended". How do i use it??
INSERT INTO PROGRAM_KPI (AMSPROGRAMID,MASTER_KPI_ID,LASTUPDATEDBYDATALOAD)
(SELECT 'PRG-026',MASTER_KPI_ID,to_char(sysdate,'dd-mon-yy hh.mi.ss') from kpi_master)
WHERE NOT EXISTS(select * from insight_master
where amsprogramid = V_PROGRAMID
and inamsscope = 1
and tickettype = 'INCIDENT'
and TICKETSUBMITDATE is not null);
Please try this..(Removing the brackets and formating the code)
INSERT INTO program_kpi
(amsprogramid, master_kpi_id, lastupdatedbydataload)
SELECT 'PRG-026', master_kpi_id, TO_CHAR (SYSDATE, 'dd-mon-yy hh.mi.ss')
FROM kpi_master
WHERE NOT EXISTS (
SELECT *
FROM insight_master
WHERE amsprogramid = v_programid AND inamsscope = 1
AND tickettype = 'INCIDENT'
AND ticketsubmitdate IS NOT NULL);
But What is the relation between table program_kpi and insight_master ?
There seems to be no join between the inner and outer subquery.

How to update table1 field by using other table and function

I have two table and one function,
Table1 contains shop_code,batch_id,registry_id
shop_code| batch_id|registry_id
123 | 100 |12
124 | 100 |13
125 | 100 |12
Table2 contains shop_code,shop_name
shop_code| shop_name
123 | need to populate
124 | need to populate
125 | need to populate
Function1 take parameter registry_id from table1 and returns shop_name
Table2 shop_name is empty I want to populate against the shop_code.
I have tried my best but all effort is gone in vain.
It will be great if someone can help I am using Oracle.
I tried below code but giving error on from keyword
update TABLE2 set T2.SHOP_NAME = T.SHOP_NAME
from(
select GET_shop_name(t1.registry_id) as shop_name ,
t1.shop_code shop_code
from TABLE1 T1
) t where t.shop_code = t1.shop_code;
I am not entirely 100% sure if I got your question right, but I believe you want something like
update
table2 u
set
shop_name = (
select
get_shop_name(t1.batch_id)
from
table1 t1
where
t1.chop_code = u.shop_code
);
can you try this approach try to put inner query to get shop name value; I have not tested it but I think approach will work for you.
update TABLE2 T2
set T2.SHOP_NAME =
(select GET_shop_name(t1.batch_id, t1.shop_code) from table1 t1 wehre t1.shop_code = t2.shop_code)
where T2.shop_name is null
You want the MERGE statement.
Something like this might work:
MERGE INTO TABLE2 t2
USING (
SELECT GET_shop_name(t1.batch_id) AS shop_name ,
t1.shop_code shop_code
FROM TABLE1 T1 ) t1
ON (t2.shop_code = t1.shop_code)
WHEN MATCHED THEN
UPDATE SET t2.shop_name = t1.shop_name
;
You'll have to excuse if the exact code above doesn't work I don't have SQL Dev where I am right now for syntax details. :)

Automate scripts

I have bunch of SQL statements and I want to put them in a script and run them together and produce an EXCEL (*.xls) file; how can I do that in toad?
Example of script
SELECT SUM(CASE
WHEN dvdn.ACDCALLS = (dvdn.ABNCALLS + dvdn.ABNCALLS1)
THEN dvdn.ABNCALLS
ELSE dvdn.ACDCALLS + dvdn.ABNCALLS - dvdn.ABNCALLS1
END) AS InboundCalls
from ccrdba.CMS_DVDN dvdn , ccrdba.VDN_DIM dim
where DIM.DW_VDN_ID = DVDN.DW_VDN_ID (+)
And DETAIL_GROUP like 'HD%'
and vdn_name not like '%ASM%'
And DIM.AGENT_GROUP <>'Smart Specialist'
And row_date BETWEEN TO_DATE('2012-SEP-01', 'YYYY-MON-DD')AND TO_DATE('2012-SEP-30', 'YYYY-MON-DD')
Second Statement
select count(*)
from xx_new.xx_online_registrations#appsread.prd.com oreg
where oreg.client_party_id = 141043767
and oreg.cti_id IS NOT NULL
and oreg.created_by = 'IVR-INTERACTIONS'
and TRUNC(CREATION_DATE) between '01-SEP-2012' and '30-SEP-2012'
and status = 'POSTED'
and last_updated_by = 'IVR-INTERACTIONS'
Like above there are about 10 SQL statements. How do I combine them together in ORACLE?
You can try "union all",
select col1 from table1
union all
select col1 from table2
union all
...

Return Oracle column names in table.column format?

Is there any setting or method I can use to get Oracle to return results in <table>.<column> format? For example:
Query:
SELECT *
FROM foo f
INNER JOIN bar b
ON b.foo_id = f.id
Desired results:
F.ID F.BLAH B.ID B.FOO_ID B.BLAH
--------------------------------------------------------
1 blah 7 1 blah
2 blah 8 2 blah
3 blah 9 2 blah
The obvious solution is to individually alias each column SELECT f.id AS F_ID, ...; however, I'm needing to export some very large legacy tables (300+ columns), so using this method would cause the queries to be enormous and impractical.
There is no "option" in Oracle to do this; you may be able to find a client that allows you to do so as this is a job that would normally be done in the client; I don't know of one.
To expand upon tbone's answer you're going to have to do this dynamically. This does not mean that you have to list every column. You would use the data dictionary, specifically all_tab_columns or user_tab_columns to create your query. It would be easier to create a view with the exact definition you want so that you can re-use it if you want.
The aim is to use the fact that the columns existence is stored in a table as a string in order to create a query to use that column. As the column names and table names are stored as strings you can use string aggregation techniques to easily create a query or DDL statement that you can then manually, or dynamically, execute.
If you're using Oracle 11g Release 2 the listagg function is available to help you:
select 'create or replace view my_view as
select '
|| listagg( table_name || '.' || column_name
|| ' as '
|| substr(table_name,1,1) || '_'
|| column_name, ', ')
within group
( order by case when table_name = 'FOO' then 0 else 1 end
, column_id
)
|| ' from foo f
join bar b
on f.id = b.foo_id'
from user_tab_columns
where table_name in ('FOO','BAR')
;
Assuming this table structure:
create table foo ( id number, a number, b number, c number);
create table bar ( foo_id number, a number, b number, c number);
This single query produces the following:
create or replace view my_view as
select FOO.ID as F_ID, FOO.A as F_A, FOO.B as F_B, FOO.C as F_C
, BAR.FOO_ID as B_FOO_ID, BAR.A as B_A, BAR.B as B_B, BAR.C as B_C
from foo f
join bar b on f.id = b.foo_id
and here's a SQL Fiddle to prove it.
In you're not using 11.2 you can achieve exactly the same results using the undocumented function wm_concat or the user-defined function stragg, which was created by Tom Kyte. Oracle Base has an article on string aggregation techniques and there are many posts on Stack Overflow.
As a little addendum you can actually create exactly what you're looking for with a small change to the above query. You can use a quoted identifier to create a column in the TABLE_NAME.COLUMN_NAME format. You have to quote it as . is not a valid character for an object name in Oracle. The benefit of this is that you gain exactly what you want. The downside is that querying the created view is a huge pain if you don't use select * from ...; selecting named columns will require them to be quoted.
select 'create or replace view my_view as
select '
|| listagg( table_name || '.' || column_name
|| ' as '
|| '"' || table_name || '.'
|| column_name || '"', ', ')
within group
( order by case when table_name = 'FOO' then 0 else 1 end
, column_id
)
|| ' from foo f
join bar b
on f.id = b.foo_id'
from user_tab_columns
where table_name in ('FOO','BAR')
;
This query returns:
create or replace view my_view as
select FOO.ID as "FOO.ID", FOO.A as "FOO.A", FOO.B as "FOO.B", FOO.C as "FOO.C"
, BAR.FOO_ID as "BAR.FOO_ID", BAR.A as "BAR.A"
, BAR.B as "BAR.B", BAR.C as "BAR.C"
from foo f
join bar b on f.id = b.foo_id
Using aliases wouldn't make the queries become impractical, its just not nearly as convenient as typing *. Use dynamic SQL to generate the columns for you:
select 'f.' || column_name || ' as F_' || column_name || ','
from all_tab_columns
where table_name = 'FOO'
order by column_id;
Do the same for any other wide tables you need, and copy/paste into your query. Also note the 30 char limit, hopefully none of your columns are over 28 in size.

Resources