Put the sample results in an array, a hash, etc using ruby and oci8 - ruby

I use ruby-2.3 and oci-8 gem. I want to make the select query:
stm = "select * from DATASERVICEUSERS t where boss<>100 and loginad is not null"
res = CONN.exec(stm).fetch_hash do |row|
#do something with row
end
CONN.logoff
How can I query the result of the whole to put for example in an array or hash, instead of cycle pass through each record? I need just a collection of elements of the result of this request.

Oci-8 doesn't provice that. The .exec method produces a cursor that you you need to process like your code demonstrates. You can fill up an array with an array of fields or a hash.
Here an example for an array
records = []
conn.exec(sql) { |record| records << record}
# records: [["xxxx", "xxxx"], ["yyyy", "yyyy"], ..]

I know this is quite an old question but I've come across this problem. I'm not as well versed in ruby but oci8 2.2.7 actually provides fetch_hash
https://www.rubydoc.info/gems/ruby-oci8/OCI8/Cursor#fetch_hash-instance_method
here's an example from my use case:
records = []
dataCursor = #odb.exec(queryUUNRData)
while((data = dataCursor.fetch_hash) != nil)
records.push data
end
dataCursor.close
the resulting dataset already includes the column names as hash key

Related

Groovy Sql rows

Hello I am trying to get rows using Groovy Sql connection but it returns me records as a List inside a List. The following:
Sql sql = new Sql(dataSource)
List<GroovyRowResult> row = sql.rows('select * from user where username=:userName and password=:password, [userName:'groovy',password:'123'])
returns the result as [[return record as map]]
Any one help me to figure out why the result is a List inside a List. How will I get it as a single level List using the rows method?
Your results are coming back as a list of maps, not a list of lists. Look at the ':' and ',' chars in the inner part. You can use standard groovy extraction of values from these.
In your case, it looks like you're using a primary key search, so will only return one result, so use firstRow in this case, so that you don't have to extract the single map result from the list.
See the documentation for the groovy Sql class for examples.
In the more general case where you are returning multiple rows, then your data probably looks like this:
[[username:"foo", password:"foopass"], [username:"bar", password:"barpass"]]
Assuming the line:
def results = sql.rows('select * from user')
You can then do things like spread operators:
assert results.username == ["foo", "bar"]
assert results.password == ["foopass", "barpass"]
or iterate over the results
results.each { println it.username }
==> foo
==> bar
or use any of the many Collection functions
println results.collect { "${it.username} -> ${it.password}" }
==> [ "foo -> foopass", "bar -> barpass" ]
I think your main issue was not recognising a single map entry in a list.
It doesn't return a List inside a List, it returns a List of Map with each map containing the columns selected from your select.
So if you want all of the usernames selected (as a List), you can just do:
def usernames = row.username
If you just want a single row, you can do:
GroovyRowResult row = sql.firstRow('select * from user where username=:userName and password=:password, [userName:'groovy',password:'123'])
And then this will effectively just be a map with each key being the field name selected, and each value being the value of the first row of each field

How to use Sequel to select one field from database

I am using Sinatra and Sequel with PostgreSQL.
After authentication, I want to welcome the user by printing their name but I cannot get only the value of the user's name from the database, it comes out as a hash.
The query is:
current_user = DB[:users].select(:username).where('password = ?', password).first
and the resulting piece of data is:
Welcome, {:username=>"Rich"}
which looks rather weird, I would prefer it to read "Welcome, Rich".
What am I doing wrong here? I tried the same query without 'first" at the end and that does not work either.
You can either pull the (single) column you selected out of the Hash you are given:
current_user = DB[:users].select(:username).where('password=?', password).first[:username]
Or you can map your results to an array of usernames and pull the first:
# Using a hash in the filter method is simpler than SQL placeholders.
current_user = DB[:users].filter(password:password).select_map(:username).first
But the best way is to get only the user you care about, and then get the name:
# Using [] on a dataset returns the first row matching the criteria
current_user = DB[:users][password:password][:username]
Try Sequel::Dataset#get. Also, as Phrogz points out, Sequel::Dataset#where can take a hash (it will securely escape values to prevent injection attacks).
current_username = DB[:users].where(password: password).get(:username)
There's also Sequel::Dataset#where_single_value, which is optimized for this exact situation:
current_username = DB[:users].select(:username).where_single_value(password: password)

Ruby DBI - How to check if a recordset is empty

Using Ruby DBI, how can I check if a record set is empty? (without iterating through it or doing a count query)
sth = dbh.prepare("select * from things WHERE created_at > '#{start}'")
sth.execute
You could always just ask the result object:
res = sth.execute
res.num_rows
The operation will have to pull down all matching records, though, so if you only need a count, you might want to select that directly.
Also escape your SQL. You cannot just put arbitrary strings in there. This is better:
sth = dbh.prepare("select * from things WHERE created_at > '%s'" % sth.escape_string(start))

Ruby datajob with mongoid

I'm trying to use ruby and mongoid in order to extract some data from an oracle database and into my mongoDB in order to perfom a couple of operations on it.
The question is:
I created my 'Record' class with includes the Mongoid::Document and set up all my fields, and have already assigned the data coming out of the oracle database, and have all my BSON objects stored in an array.
Now my question is: How I save them?
Here's my piece of code
query = db.report # Sequel Object
query.each do |row|
r = Record.new #Mongoid class
r.directory_name = row[:directory_name]
r.directory_code = row[:directory_id]
r.directory_edition = row[:edition]
r.last_updated = row[:updated]
r.canvass = row[:canvass_id]
r.specialty_item = row[:item]
r.production_number = row[:prodnr]
r.status = row[:exposure_status]
r.scanned_date = row[:scandate]
r.customer_id = row[:customer_id]
r.sales_rep = row[:sales_rep_name]
r.phone = row[:phone]
r.customer_name = row[:customer_name]
records << r
end
You would need to do Record.collection.insert(records). Although note that this will skip any validations you have written in your Mongoid model but will be a little faster than creating mongoid records and saving them, as it will use the ruby mongo driver directly. You should only do this if you know that data is consistent.
If you want to do all the validations on your data before saving them in MongoDB, you should create a model instead of putting them in an array.
So you can persist the data extracted in MongoDB in three ways according to your preferences:
Insert all records at once using mongo driver, but beware the array you are creating can be huge:
query.each do |row|
.....
end
Record.collection.insert(records)
Insert one record at a time using mongo driver(replace records << r with new line)
query.each do |row|
.....
Record.collection.insert(r)
end
Insert one record at a time using Mongoid and all the validations and callbacks(replace records << r with new line)
query.each do |row|
.....
r.save
end
update: Missed that you are already creating the record hence the mongo driver suggestions. If you want to use mongo driver directly, you should use a hash instead of Mongoid model. i.e instead of
r = Record.new
r.status = row[:status]
# copy more data
you should do
r = {}
r[:status] = row[:status]
# copy more data

replacing a value in a json array with sinatra

I have records with a 'resource' field which can contain multiple resources. When I return this data, I need to iterate over this field and return an individual record for each value in the field. I am currently using sinatra and am able to interate over the fields okay, but I am having difficulty replacing the field in the json array.
For example
event: Name
resources: resourceA, resourceB, resourceC
This record needs to be returned as 3 uniqe records/events with only one resource per record.
With the code listed below, I am getting three records, but all three records are coming back with the same resource value (resourceC)
Here is my code
docs = #db.view('lab/events', :startkey => params[:startDate], :endkey => endSearch)['rows']
rows = Array.new
docs.each do |doc|
resources = doc['value']['resources'].split(",")
resources.each do |r|
doc['value']['resources'] = r
rows.push(doc['value'])
end
end
Any help is greatly appreciated.
Thanks
Chris
if you use the ruby gem "json" you can convert the json string to a hash
require 'json'
converted_hash = JSON(json_string).to_hash
This should be much easier to manage.
You can then turn the hash to a JSON string:
new_json_string = converted_hash.to_json
Basically what is happening is ruby is seeing all three records as the same record so as the hash value is updated on one record, it impacts all other records that were created from the same doc. To get around this, I acutally needed to create a duplicate record each time through and modify it's value.
docs = #db.view('lab/events', :startkey => params[:startDate], :endkey => endSearch)['rows']
rows = Array.new
docs.each do |doc|
resources = doc['value']['resources'].split(",")
resources.each do |r|
newDoc = doc['value'].dup # <= create a duplicate record and update the value
newDoc["resources"] = r
rows.push(newDoc)
end
end

Resources