How to get next id in GRAILS? - oracle

I need to get the next available id in a sequence, using GORM or native query.
How can I do this?
I'm using oracle.
UPDATE:
I need this value BEFORE insert, because my row will use this value.
I have table called IMAGE, with column FILE_NAME, like this:
- ID | FILE_NAME
- 123 | foo_bar_123.png
- 124 | xxx_yyy_124.png
Tks a lot.

Why do you need the value before the insert? Could you get the information as part of the insert using the RETURNING clause, i.e.
INSERT INTO table_name( id, file_name )
VALUES( some_sequence.nextval, <<bind variable>> )
RETURNING id INTO <<bind variable>>
Or access it after the insert using
SELECT sequence_name.currval
FROM dual
The currval of a sequence returns the most recent value of the sequence produced in the current session so it is actually thread-safe. Since sequences are designed to provide numbers in a highly concurrent environment, you cannot in general find out what the nextval is going to be unless you actually fetch the nextval. Even if you could, there is no guarantee that another thread won't come along and get the value you peeked at before your INSERT took place so it wouldn't be safe to peek at the nextval in a multi-user environment.

I adapted #Cave tips.
So, my solution is:
Change my mapping from:
class Image {
...
id column: "ID", generator: "sequence", params: [sequence:"MY_SEQUENCE"]
...
}
to:
class Image {
...
id column: "ID", generator: "assigned"
...
}
And set id mannualy using this:
def getLastImageId(){
def sql = "SELECT MY_SEQUENCE.nextval FROM dual"
def query = sessionFactory.currentSession.createSQLQuery(sql);
def result = query.list()
return result[0]
}
...
newImage.id = getLastImageId()
newImage.fileName = "foo_bar_${newImage.id}.png"

Related

Project a single column of a table filtered by tag from act as taggale

Currently the only way I know to sub select in rails is with arel,
for exmaple -
sub = x.where(y:'x').project(:id)
select = a.where(a[:x_id].in(sub))
question is,
if x is using the acts as taggable on gem and need to filtered by a specific tag, use with tagged_with method.
How can I still achive same database efficiency, it looks like the tagged with method override the projection.
thanks,
You don't need Arel to build sub selects in Rails:
sub = X.where(y: 'x')
select = A.where(x_id: sub)
generates the following SQL, assuming A's table name is as and X's is xs:
SELECT "as".* FROM "as" WHERE "as"."x_id" IN (SELECT "xs"."id" FROM "xs" WHERE "xs"."y" = 'x')
Testing with tagged_with worked: A.where(x_id: X.tagged_with('my_tag')) generates the expected SQL, at least for Rails 5.1, version on which I've tested.
Edit
You can specify the column used inside the subselect if needed. If you don't specify it, the primary key column is the default:
sub = X.where(y: 'x').select(:x_y_id)
select = A.where(x_id: sub)
will generate the following SQL:
SELECT "as".* FROM "as" WHERE "as"."x_id" IN (SELECT "xs"."x_y_id" FROM "xs" WHERE "xs"."y" = 'x')

For table cmdb_rel_ci, I want to retrieve unique parent.sys_class_name with count for "type=In Rack::Rack contains"

For table cmdb_rel_ci, I want to retrieve unique parent.sys_class_name with count for "type=In Rack::Rack contains". I am doing practice in out of the box instance.
At table level URL is as below:
URL
I want to retrieve result from above URL with my below script.
var count = new GlideAggregate('cmdb_rel_ci');
count.addQuery('type','e76b8c7b0a0a0aa70082c9f7c2f9dc64');// sys_id of type In Rack::Rack contains e76b8c7b0a0a0aa70082c9f7c2f9dc64
count.addAggregate('COUNT', 'parent.sys_class_name');
count.query();
while(count.next()){
var parentClassName = count.parent.sys_class_name.toString();
var parentClassNameCount = count.getAggregate('COUNT','parent.sys_class_name');
gs.log(parentClassName + " : " + parentClassNameCount );
}
The issue is I am getting parentClassName empty.
Try this instead:
var parentClassName = count.getValue("parent.sys_class_name")
Since it's a GlideAggregate query (instead of GlideRecord), the query being issued isn't returning all of the fields on the target table. With GlideRecord, dot-walking through a reference field (e.g. parent.sys_class_name) automatically resolves that referenced record to provide access to its field values. This is made possible by the fact that the driving/original query brought back the value of the parent field. This is not happening with GlideAggregate. The query in this case basically looks like:
SELECT cmdb1.`sys_class_name` AS `parent_sys_class_name`, count(*)
FROM (cmdb_rel_ci cmdb_rel_ci0 LEFT JOIN cmdb cmdb1 ON cmdb_rel_ci0.`parent` = cmdb1.`sys_id` )
WHERE cmdb_rel_ci0.`type` = 'e76b8c7b0a0a0aa70082c9f7c2f9dc64'
GROUP BY cmdb1.`sys_class_name`
ORDER BY cmdb1.`sys_class_name`
So, you actually have access specifically to that dot-walked sys_class_name that's being grouped, but not through the dot-walk. The call to getValue("parent.sys_class_name") is expectedly resolved to the returned column aliased as parent_sys_class_name.
That being said, what you're doing probably should also work, based on user expectations, so you've not done anything incorrect here.

jruby jdbc how to get id of inserted row

I have insert query that works, but I can't get ID of created row in return. How can I achieve that? having this:
conn = Java::JavaSql::DriverManager.getConnection(url)
st = conn.create_statement
rs = st.execute_update(query)
How can I get id?
more of a JDBC question that depends on the DB/driver used.
generally st.generated_keys gives you a result set of the IDs
also read: How to get the insert ID in JDBC?

Slick/Oracle PLAIN SQL Get auto generated ID after insert

I am trying to run a query via Slick in Scala that will insert a record into an Oracle db and return the auto generated ID as the result. I see that this is possible using Slick's syntax but is this possible using a plain SQL query? With below code I can only get a return value of -1.
val name = "Bob"
db.run(sql"""DECLARE NEW_PERSON_ID;
BEGIN
INSERT INTO TB_PEOPLE (ID, NAME)
VALUES(SEQ_PEOPLE.NEXTVAL, $name)
RETURNING ID INTO NEW_PERSON_ID;
END;""".as[Int])
It seems that Slick doesn't support output parameters so using Oracle's returning syntax won't work. A workaround I found is to first generate an ID and then insert using that ID (requires 2 queries). The queries are wrapped in a transaction.
val name = "Bob"
val action = for {
newPersonId <- sql"""SELECT SEQ_PEOPLE.NEXTVAL FROM DUAL""".as[Int]
_ <- sqlu"""INSERT INTO TB_PEOPLE (ID, NAME) VALUES ($newPersonId, $name)"""
}
db.run(action.transactionally)

Can I FlexMock a method to raise an exception on the first call, then return a valid object on the second call?

I'm working on some Ruby code that needs to create primary keys on existing MySQL database tables. It needs to detect and fix duplicates to allow index creation to succeed, with the following algorithm:
# 1. Query
ALTER TABLE foo ADD PRIMARY KEY (id)
# 2. Handle exception:
Duplicate entry '3761290' for key 'PRIMARY' (Mysql::Error)
# 3. Query:
SELECT COUNT(1) FROM TABLE foo WHERE id = 3761290
# 4. (Assuming 5 rows were returned from the previous query) Query:
DELETE FROM TABLE foo WHERE id = 3761290 LIMIT 4 OFFSET 1
# 5. retry ALTER TABLE query
The test looks something like this:
def test_create_primary_key
table = 'foo'
db = flexmock
db.should_receive(:prepare).
with("ALTER TABLE #{table} ADD PRIMARY KEY (id)").
twice.
and_raise(Mysql::Error, "Duplicate entry '3761290' for key 'PRIMARY'")
db.should_receive(:prepare).
with("SELECT COUNT(1) FROM #{table} WHERE id = ?").
once.
and_return(MockStatement.new [ [5] ])
db.should_receive(:prepare).
with("DELETE FROM #{table} WHERE id = ? LIMIT 4 OFFSET 1").
once.
and_return(MockStatement.new [ [5] ])
indexer = Indexer.new :database_handle => db
indexer.create_indexes table
end
The problem is that the code will run in an infinite loop (unless it has a max retries condition, which it may well do), since it will continue to get an exception from the FlexMock'd db.
Ideally, the mock should be able to raise an exception the first time, then return a valid statement handle the second time. The block form of #with might work here, but I'd like to do it in a clean way if at all possible.
Any ideas?
I forgot that since Ruby (generally) conforms to The Principle of Least Astonishment, one should just try what makes sense and see what happens:
def test_yield_then_return
mock = flexmock
flexmock(mock).should_receive(:foo).
with(:bar).
and_raise(RuntimeError).
and_return(true)
assert_raises(RuntimeError) { mock.foo :bar }
assert mock.foo(:bar)
end
Does what it says on the tin. :)

Resources