how to run inline query in mysql - java

I am working with TSP(Traveling salesmen problem) Solution in mysql.
for that we are going to develop procedure where i want to execute following query
-- variable coming from java
CREATE PROCEDURE solve_tsp(
inout ids varchar(21845);
)
begin
declare ret_ids varchar(21845);
-- some code
while length(ids) > 0 do
-- some assignment
SELECT to_id,distance into #l_tmp_id,#l_distance FROM mst_distance_matrix WHERE from_id =',#l_tmp_id,' AND
to_id IN (ids) -- ids is variable contains comma delimited string.
order by distance desc limit 1
-- concat value of to_id in ret_ids variable and then remove from ids variable
end while;
select ret_ids;
end;

You should look here.
http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-prepared-statements.html
Example:
PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
SET #a = 3;
SET #b = 4;
EXECUTE stmt1 USING #a, #b;
DEALLOCATE PREPARE stmt1;
See also:
Dynamic Query in MySQL

Related

How to upsert(update if exists, else insert) into a table using jdbcTemplate [duplicate]

The UPSERT operation either updates or inserts a row in a table, depending if the table already has a row that matches the data:
if table t has a row exists that has key X:
update t set mystuff... where mykey=X
else
insert into t mystuff...
Since Oracle doesn't have a specific UPSERT statement, what's the best way to do this?
The MERGE statement merges data between two tables. Using DUAL
allows us to use this command. Note that this is not protected against concurrent access.
create or replace
procedure ups(xa number)
as
begin
merge into mergetest m using dual on (a = xa)
when not matched then insert (a,b) values (xa,1)
when matched then update set b = b+1;
end ups;
/
drop table mergetest;
create table mergetest(a number, b number);
call ups(10);
call ups(10);
call ups(20);
select * from mergetest;
A B
---------------------- ----------------------
10 2
20 1
The dual example above which is in PL/SQL was great becuase I wanted to do something similar, but I wanted it client side...so here is the SQL I used to send a similar statement direct from some C#
MERGE INTO Employee USING dual ON ( "id"=2097153 )
WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john"
WHEN NOT MATCHED THEN INSERT ("id","last","name")
VALUES ( 2097153,"smith", "john" )
However from a C# perspective this provide to be slower than doing the update and seeing if the rows affected was 0 and doing the insert if it was.
An alternative to MERGE (the "old fashioned way"):
begin
insert into t (mykey, mystuff)
values ('X', 123);
exception
when dup_val_on_index then
update t
set mystuff = 123
where mykey = 'X';
end;
Another alternative without the exception check:
UPDATE tablename
SET val1 = in_val1,
val2 = in_val2
WHERE val3 = in_val3;
IF ( sql%rowcount = 0 )
THEN
INSERT INTO tablename
VALUES (in_val1, in_val2, in_val3);
END IF;
insert if not exists
update:
INSERT INTO mytable (id1, t1)
SELECT 11, 'x1' FROM DUAL
WHERE NOT EXISTS (SELECT id1 FROM mytble WHERE id1 = 11);
UPDATE mytable SET t1 = 'x1' WHERE id1 = 11;
None of the answers given so far is safe in the face of concurrent accesses, as pointed out in Tim Sylvester's comment, and will raise exceptions in case of races. To fix that, the insert/update combo must be wrapped in some kind of loop statement, so that in case of an exception the whole thing is retried.
As an example, here's how Grommit's code can be wrapped in a loop to make it safe when run concurrently:
PROCEDURE MyProc (
...
) IS
BEGIN
LOOP
BEGIN
MERGE INTO Employee USING dual ON ( "id"=2097153 )
WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john"
WHEN NOT MATCHED THEN INSERT ("id","last","name")
VALUES ( 2097153,"smith", "john" );
EXIT; -- success? -> exit loop
EXCEPTION
WHEN NO_DATA_FOUND THEN -- the entry was concurrently deleted
NULL; -- exception? -> no op, i.e. continue looping
WHEN DUP_VAL_ON_INDEX THEN -- an entry was concurrently inserted
NULL; -- exception? -> no op, i.e. continue looping
END;
END LOOP;
END;
N.B. In transaction mode SERIALIZABLE, which I don't recommend btw, you might run into
ORA-08177: can't serialize access for this transaction exceptions instead.
I'd like Grommit answer, except it require dupe values. I found solution where it may appear once: http://forums.devshed.com/showpost.php?p=1182653&postcount=2
MERGE INTO KBS.NUFUS_MUHTARLIK B
USING (
SELECT '028-01' CILT, '25' SAYFA, '6' KUTUK, '46603404838' MERNIS_NO
FROM DUAL
) E
ON (B.MERNIS_NO = E.MERNIS_NO)
WHEN MATCHED THEN
UPDATE SET B.CILT = E.CILT, B.SAYFA = E.SAYFA, B.KUTUK = E.KUTUK
WHEN NOT MATCHED THEN
INSERT ( CILT, SAYFA, KUTUK, MERNIS_NO)
VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);
I've been using the first code sample for years. Notice notfound rather than count.
UPDATE tablename SET val1 = in_val1, val2 = in_val2
WHERE val3 = in_val3;
IF ( sql%notfound ) THEN
INSERT INTO tablename
VALUES (in_val1, in_val2, in_val3);
END IF;
The code below is the possibly new and improved code
MERGE INTO tablename USING dual ON ( val3 = in_val3 )
WHEN MATCHED THEN UPDATE SET val1 = in_val1, val2 = in_val2
WHEN NOT MATCHED THEN INSERT
VALUES (in_val1, in_val2, in_val3)
In the first example the update does an index lookup. It has to, in order to update the right row. Oracle opens an implicit cursor, and we use it to wrap a corresponding insert so we know that the insert will only happen when the key does not exist. But the insert is an independent command and it has to do a second lookup. I don't know the inner workings of the merge command but since the command is a single unit, Oracle could execute the correct insert or update with a single index lookup.
I think merge is better when you do have some processing to be done that means taking data from some tables and updating a table, possibly inserting or deleting rows. But for the single row case, you may consider the first case since the syntax is more common.
A note regarding the two solutions that suggest:
1) Insert, if exception then update,
or
2) Update, if sql%rowcount = 0 then insert
The question of whether to insert or update first is also application dependent. Are you expecting more inserts or more updates? The one that is most likely to succeed should go first.
If you pick the wrong one you will get a bunch of unnecessary index reads. Not a huge deal but still something to consider.
Try this,
insert into b_building_property (
select
'AREA_IN_COMMON_USE_DOUBLE','Area in Common Use','DOUBLE', null, 9000, 9
from dual
)
minus
(
select * from b_building_property where id = 9
)
;
From http://www.praetoriate.com/oracle_tips_upserts.htm:
"In Oracle9i, an UPSERT can accomplish this task in a single statement:"
INSERT
FIRST WHEN
credit_limit >=100000
THEN INTO
rich_customers
VALUES(cust_id,cust_credit_limit)
INTO customers
ELSE
INTO customers SELECT * FROM new_customers;

execute anonymous pl/sql block file with values from java

I have an anonymous pl/sql block in an sql file and I want to execute and assign values to it in Java. My sql block looks like this
DECLARE
someInput1 NUMBER(1);
someInput2 NUMBER(2);
someString1 VARCHAR(100);
BEGIN
someInput1 := ‘&1’;
someInput2 := ‘&2’;
--get name in table A
BEGIN
SELECT a.value INTO someString1
FROM TABLE_A a
WHERE a.id = someInput1;
END;
UPDATE TABLE_B b
SET b.someStringRow = someString1
WHERE b.someIntRow = someInput2;
COMMIT;
END;
/
exit;
What I am planning to do is load the sql file in a Java String, change ‘&1’ to ?1 and execute it as a CallableStatement. However, I am getting
PLS-00103: Encountered the symbol “” when expecting one of the following
begin function package pragma procedure subtype us <an identifier> <a double quoted delimited identifier> form current cursor
Error occured at lines in DECLARE section
Is my approach an acceptable solution, if yes, what may be wrong in my approach?
Are there other better solution for my problem? Thanks
you have to remove quote marks, and replace &1 with :1, and you should be fine, also, you will need remove '/' and exit; and they relate to sqlplus and not to pl/sql directly

Detect, delete empty columns and update database in sql, oracle

I have 100 of columns and some of the doesn't have any values inside(they are empty) how can I search for empty columns and delete from table and update database? I tried this query but it doesnt work. It shows 0 rows selected. After selecting how can I update the database?
select table_name, column_name
from all_tab_columns
where table_name='some_table'
and column_name is NULL;
Thanks,
You are querying a data dictionary view. It shows meta-data, in formation about the database. This view, ALL_TAB_COLUMNS, shows information for every column of every table (you have privileges on). Necessarily COLUMN_NAME cannot be null, hence your query returns no rows.
Now what you want to do is query every table and find which columns have no data in them. This requires dynamic SQL. You will need to query ALL_TAB_COLUMNS, so you weren't completely off-base.
Because of dynamic SQL this is a programmatic solution, so the results are displayed with DBMS_OUTPUT.
set serveroutput on size unlimited
Here is an anonymous block: it might take some time to run. The join to USER_TABLES is necessary because columns from views are included in TAB_COLUMNS and we don't want those in the result set.
declare
dsp varchar2(32767);
stmt varchar2(32767);
begin
<< tab_loop >>
for trec in ( select t.table_name
from user_tables t )
loop
stmt := 'select ';
dbms_output.put_line('table name = '|| trec.table_name);
<< col_loop >>
for crec in ( select c.column_name
, row_number() over (order by c.column_id) as rn
from user_tab_columns c
where c.table_name = trec.table_name
and c.nullable = 'Y'
order by c.column_id )
loop
if rn > 1 then stmt := concat(stmt, '||'); end if;
stmt := stmt||''''||crec.column_name||'=''||'
||'to_char(count('||crec.column_name||')) ';
end loop col_loop;
stmt := stmt || ' from '||trec.table_name;
execute immediate stmt into dsp;
dbms_output.put_line(dsp);
end loop tab_loop;
end;
sample output:
table name = MY_PROFILER_RUN_EVENTS
TOT_EXECS=0TOT_TIME=0MIN_TIME=0MAX_TIME=0
table name = LOG_TABLE
PKG_NAME=0MODULE_NAME=0CLIENT_ID=0
PL/SQL procedure successfully completed.
SQL>
Any column where the COUNT=0 has no values in it.
Now whether you actually want to drop such columns is a different matter. You might break programs which depend on them. So you need an impact analysis first. This is why I have not produced a program which automatically drops the empty columns. I think that would be dangerous practice.
It is crucial that changes to our database structure are considered and audited. So if I were ever to undertake an exercise like this I would alter the output from the program above so it produced a script of drop column statements which I could review, edit and keep under source control.

Listagg function and ORA-01489: result of string concatenation is too long

When i run the following query:
Select
tm.product_id,
listagg(tm.book_id || '(' || tm.score || ')',',')
within group (order by tm.product_id) as matches
from
tl_product_match tm
where
tm.book_id is not null
group by
tm.product_id
Oracle returns the following error:
ORA-01489: result of string concatenation is too long
I know that the reason it is failing is that the listagg function is trying to concatenate a the values which are greater than 4000 characters which is not supported.
I have seen the alternative example described here - http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php but they all require the use of functions or procedure.
Is there a solution that is pure SQL without having to call a function or stored procedure and being able to read the value using standard JDBC?
The other difficulty i have is that most string aggregation examples i have seen shows examples with how to read the value as is. In my example about i am modifying the value first (i.e. i am aggregating two columns).
you can use xml functions to do it which return a CLOB. JDBC should be just fine with that.
select tm.product_id,
rtrim(extract(xmlagg(xmlelement(e, tm.book_id || '(' || tm.score || '),')),
'/E/text()').getclobval(), ',')
from tl_product_match tm
where tm.book_id is not null
group by tm.product_id;
eg: http://sqlfiddle.com/#!4/083a2/1
Why not use nested tables?
set echo on;
set display on;
set linesize 200;
drop table testA;
create table testA
(
col1 number,
col2 varchar2(50)
);
drop table testB;
create table testB
(
col1 number,
col2 varchar2(50)
);
create or replace type t_vchar_tab as table of varchar2(50);
insert into testA values (1,'A');
insert into testA values (2,'B');
insert into testB values (1,'X');
insert into testB values (1,'Y');
insert into testB values (1,'Z');
commit;
-- select all related testB.col2 values in a nested table for each testA.col1 value
select a.col1,
cast(multiset(select b.col2 from testB b where b.col1 = a.col1 order by b.col2) as t_vchar_tab) as testB_vals
from testA a;
-- test size > 4000
insert into testB
select 2 as col1, substr((object_name || object_type), 1, 50) as col2
from all_objects;
commit;
-- select all related testB.col2 values in a nested table for each testA.col1 value
select a.col1,
cast(multiset(select b.col2 from testB b where b.col1 = a.col1 order by b.col2) as t_vchar_tab) as testB_vals
from testA a;
I'm no java expert, but this has been around for some time and I'm sure java can pull the values out of the nested table. And, no need to tokenize some delimited string on the other end.
I have seen the alternative example described here - http://www.oracle-base.com/articles/misc/string-aggregation-techniques.php but they all require the use of functions or procedure.
No they don't. Scroll down and you'll see several options that don't require pl/sql.

Java Oracle jdbc COLUMN statement

The problem is following
By executing the below queries in SQL Plus, everything is working perfect:
column firstname new_value v_firstname
select firstname from tbcustomer where customer_id = 111
select '&v_firstname', wrk.* from tbwork where customer_id = 111
But when when i tried to execute these queries from Java program, i get java.sql.SQLException: ORA-00900: invalid SQL statement on the first SQL query
Connection connection = null;
Statement stat = null;
String query = "column due_date new_value v_due_date";
try {
// Load the JDBC driver
String driverName = "oracle.jdbc.driver.OracleDriver";
Class.forName(driverName);
connection = DriverManager.getConnection(url, username, password);
stat = connection.createStatement();
boolean res_num = stat.execute(query);
} catch (ClassNotFoundException e) {
// Could not find the database driver
} catch (SQLException e) {
e.printStackTrace();
}
Now the question is how to overcome this error and execute first query or do you have any other solution to define variable on the oracle session and use it in other SQL statements.
For instance third query is one of the many queries that i need to execute and all of them will have same first name field
column is a SQL*Plus command. It is not valid in SQL or PL/SQL so you cannot use it in a Java application.
Substitution variables like &v_firstname are also a SQL*Plus construct-- they are not valid in SQL or PL/SQL so you cannot use them in a Java application.
If your goal is to get the firstname from tbcustomer and all the columns from tbwork in a single query, you would need to join the two tables. Assuming that both tables have a customer_id column and that is how the two tables are supposed to be joined
SELECT cust.firstname,
work.*
FROM tbcustomer cust
JOIN tbwork work ON (cust.customer_id = work.customer_id)
WHERE cust.customer_id = 111
Assuming that you will be executing this query for multiple customer_id values, however, 111 should be a bind variable instead of a literal and your Java code should be using a PreparedStatement to prepare the SQL statement, then binding a value like 111 using the setInt method before executing the query.
If you want to break this into two database calls, you can simply do something like
PreparedStatement stmtGetFirstName = connection.prepareStatement("select firstname from tbcustomer where customer_id = ?");
stmtGetFirstName.setInt( 1, 111 );
ResultSet rsGetFirstName = stmtGetFirstName.executeQuery();
String firstName = rsGetFirstName.getString();
PreparedStatement stmtGetWork = connection.prepareStatement("select ?, work.* from tbwork where customer_id = ?");
stmtGetWork.setString( 1, firstName );
stmtGetWork.setInt( 2, 111 );
ResultSet rsGetWork = stmtGetWork.executeQuery();
If you can guarantee that all 600 million executions will occur in the same database session, you could use a database context. You would need to create the context and the package it uses in the database
SQL> create or replace context fname_ctx using scott.pkg_get_fname;
Context created.
SQL> ed
Wrote file afiedt.buf
1 create or replace package pkg_get_fname
2 is
3 procedure set_fname( p_customer_id in number );
4 function get_fname return varchar2;
5* end;
SQL> /
Package created.
SQL> create or replace package body pkg_get_fname
2 is
3 procedure set_fname( p_customer_id in number )
4 as
5 begin
-- Obviously, you'd get the data here from your table rather than hard-coding 'Bob'
6 dbms_session.set_context( 'fname_ctx', 'fname', 'Bob' );
7 end;
8
9 function get_fname
10 return varchar2
11 is
12 l_fname varchar2(100);
13 begin
14 l_fname := sys_context( 'fname_ctx', 'fname' );
15 return l_fname;
16 end;
17 end;
18 /
Package body created.
From Java, you could then call pkg_get_fname.set_fname(111) to set the context and use the function pkg_get_fname.get_fname in your query.
It seems odd, however, to be concerned about performance and to be planning to execute 600 million queries from Java against the database. That's going to involve a ton of round-trips over the network between the middle tier and the database server-- if you're really concerned about performance, you'd push that work to stored procedures in the database to eliminate the network round-trips. And the fact that you're executing them so many times makes me suspect that you're doing a lot of row-by-row processing rather than letting the database do set-based operations. That's also going to be a major source of poor performance. Plus, databases are born to join, so it's pretty unusual for a simple join like this to add appreciably to the cost of a query assuming that proper indexes are in place.

Categories

Resources