We have a java database abstraction that does a number of inserts for us. At runtime we'll know the table name, the column names to insert and the values. From that we generate a prepared statement and do the insert.
In sql server land we would tack on select id = ##identity to the end of the generated sql to get the newly generated id returned by the query.
Now that we're migrating to postgres this no longer works. It's my understanding that in postgres you can do ,
insert into foo(a, b) values('a', 'b') returning ID
Our problem is that at runtime we don't know the name of the ID column nor do we know the name of the sequence. Is there any way to generically get the value of the newly inserted sequence without knowing the name of the sequence or the name of the column?
If your insert is not triggering further inserts, you can use SELECT LASTVAL(); right after your insert statement
Related
My requirement is I want to determine type of sql query so that I can choose jdbcTemplate method accordingly.
Suppose my sql query is of type insert or update then I will choose
String sql ="insert/update sql query";
jdbcTemplate.update(sql);
jdbcTemplate method and if type of my sql query is select then I will choose
String sql ="select sql query";
jdbcTemplate.query(sql);
jdbcTemplate method.
How to determine type of sql query in java effectively?
Which jdbcTemplate method to choose if my query contains both update and select sql statements? e.g.
update table set column_name="abc" where column_name in (select
column_name from table where column_name ="xyz");
Update: In reality I am accepting sql queries from the users of my application from the web form so that is the reason where actual problem arises because user can post any type of sql query through form and I want to choose specific jdbcTemplate method depending upon type of query.
in Oracle you can parse a query before executing it
declare
l_theCursor integer default dbms_sql.open_cursor;
begin
dbms_sql.parse( l_theCursor, 'SELECT 1 FROM DUAL', dbms_sql.native );
end;
which is a good practice anyway since you will be receiving your SQL from user input. if the statement is not valid you will get the appropriate error message. Of course the statement is not executed by the above.
After parsing the statement you can query v$sql to find out the command_type:
select command_type, sql_text
from v$sql t
where sql_text = 'SELECT 1 FROM DUAL';
The various commands_types are like so:
2 -- INSERT
3 -- SELECT
6 -- UPDATE
7 -- DELETE
189 -- MERGE
you can get the full list by select * from audit_actions order by action
Hope that helps :)
SELECT subqueries are irrelevant for the final result. So the command, the first verb is indicative of the result (int updateCount vs. ResultSet).
boolean isSqlSelect = sql.toUpperCase().startsWith("SELECT")
|| sql.toUpperCase().startsWith("WITH");
You can run an SQL UPDATE query via the .select() method, and you can run an SQL SELECT query via the .update() method.
So why are there 2 different methods?
The update method returns a single number; this number represents the amount of changed/created rows.
The select method returns a resultset, which is like a little table: It has a number of (typed and named) columns, and you can walk through the resultset, getting a row's worth of data every time.
In practice, running a SELECT SQL statement via .update() will run the select (and if that select somehow writes to the DB, for example because you run SELECT NEXTVAL('someSequence'), those effects do occur, but you get 0 back because it didn't change/add any rows to any tables. If you run an UPDATE SQL via .select(), the updates go through, and you get an empty resultset back, or possibly a resultset with 1 column of some numberic type, and one row, with the one value that row has being equal to the update count. It depends on the JDBC driver.
There's another method (execute), which returns nothing. The same applies here: If you run an UPDATE via this method, it still works, you just don't get the updatecount back.
My advice: Use .select for all of it, and write a nice renderer that reports the resultset back to the user.
If you'd like to investigate some code that's already done all this, check out the h2 console.
I'm trying to use jOOQ to generate the following SQL statement:
SELECT id, name
FROM students
ORDER BY id DESC
LIMIT 50;
To generate the above statement with jOOQ:
String sql = DSL.using(SQLDialect.POSTGRES).select(
field("id"),
field("name"))
.from("students")
.orderBy(field("id").desc())
.limit(inline(50))
.getSQL();
But I get the following:
select id, name from students order by id desc limit 50 offset ?
How do I remove the OFFSET clause? I know that I can specify the offset value to 0, which is same as omitting the OFFSET clause, but I want to know whether I can completely remove it from the generated SQL statement.
Thank you.
You're right, jOOQ 3.4.2 currently renders an OFFSET clause for PostgreSQL, regardless of whether it was specified by users through the API or not. That could probably be improved. I've created issue #3577 for this.
Currently, there isn't really an "easy" way to change the generated SQL in this case. You could be implementing an ExecuteListener, and patch the generated SQL - but you'd also have to get rid of the bind value.
I'm working with MySQL Workbench 5.2 CE and I'm having trouble building a trigger. I have a table set up like so, with the 'id' field being an auto increment
TABLE
addr VARCHAR
id INT
and a batch statement written in Java
String state1 = "insert ignore into TABLE(addr) values (?);"
and a trigger set up like so
USE DB_NAME;
DELIMITER $$
CREATE TRIGGER `check_addr` BEFORE INSERT ON tableFOR EACH ROW
-- Edit trigger body code below this line. Do not edit lines above this one
IF ( SELECT * FROM table WHERE addr = NEW.addr ) = 0
THEN insert into table(addr) values (NEW.addr);
END IF;
All of which is me trying to avoid gaps in my auto-increment values. I'm using the table to store a lot of network-related information, so the potential gaps in the auto-increment field would get pretty massive.
The goal with the trigger is to avoid the insert statement (and subsequent increment of the auto increment field) and silently abort. This way the auto-increment values stay consecutive.
A quick note: the addr field is a PK.
Thanks.
EDIT 12/4/2013
Just as an update, I dropped the AI field and opted instead for a composite key. Uses slightly more disk space, but I got clever with normalizing other fields so it worked out in the end. Thanks for the help!
No, no, no no!
Don't misuse the auto-increment primay key in such way! It is meant to be auto-generated and untouched. Just leave it.
If you need an indicator in which order your rows where inserted then use another column. For instance a datetime column with a default value like current_timestamp. That way it will be filled automatically too and you don't have to do anything.
I'm trying to do a comparison between the data of a table of a SQLServer database before and after some action.
I'm saving the first data in a file (actually I'm saving the MD5 of the data, but not relevant), so I can compare the new data with it after the action.
The first problem is that the data returned by the query is not always in the same order.
So to solve this problem I thought about using the ORDER BY clause to order the data.
Here comes the second problem. I'm executing a query defined by the user, so the query, and the table may be different.
So here is the question: How can I ORDER BY the PRIMARY_KEY (one or multiple) without previous knowledge of what table will be used??
Any other solution will be also welcomed,
Thanks for your time and effort,
You can use dynamic sql and query the meta tables to discover what the primary key is
SELECT column_name
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE
WHERE OBJECTPROPERTY(OBJECT_ID(constraint_name), 'IsPrimaryKey') = 1
AND table_name = 'Person'
With dynamic sql you construct your sql statement like a string and hand it over to sp_executeSQL
More info at http://msdn.microsoft.com/en-us/library/ms188001.aspx
I'm trying to do a comparison between the data of a table of a
SQLServer database before and after some action.
If you are using SQL Server 2008, you can use CDC
Do you really need to order by the primary key? If not you can do
ORDER BY 1, 2, 3
that will order by column 1, 2 and 3 regardless the name of the column.
That would work on the PK if you have your Primary key on the first column of the table
I have an table (in ORADB) containing two columns: VARCHAR unique key and NUMBER unique key generated from an sequence.
I need my Java code to constantly (and in parallel) add records to this column whenever a new VARCHAR key it gets, returning the newly generated NUMBER key. Or returns the existing NUMBER key when it gets an existing VARCHAR (it doesn't insert it then, that would throw an exception of course due to the uniq key violation).
Such procedure would be executed from many (Java) clients working in parallel.
Hope my English is understandable :)
What is the best (maybe using PL/SQL block instead of Java code...) way to do it?
I do not think you can do better than
SELECT the_number FROM the_table where the_key = :key
if found, return it
if not found, INSERT INTO the_table SELECT :key, the_seq.NEXT_VAL RETURNING the_number INTO :number and COMMIT
this could raise a ORA-00001(duplicate primary key insert)
if the timing is unlucky. In this case, SELECT again.
Not sure if JDBC supports RETURNING, so you might need to wrap it into a stored procedure (also saves database roundtrips).
You can use an index-organized table (with the_key as primary key), makes the lookup faster.