Use Hash with Redundant Items in sqlite3 Bind - ruby

I'm trying to run an INSERT query such as the following:
Query = "INSERT INTO t (x,y,z) VALUES (:aval,:bval,:cval)"
Using the following format, I can use a hash to insert the actual values:
db.execute(Query,{"aval" => "1", "bval" => "2", "cval" => "3"})
My problem is that the values are already in a hash that has some redundant values, e.g.:
{"aval" => "1", "bval" => "2", "cval" => "3", "dval" => "4"}
Since dval is not one of the required parameters, I get the error -
SQLite3::Exception: no such bind parameter
Of course, I may be wrong and the error may be due to a different reason.
It would be great if there were a way to overcome this using SQLite3. Alternatively, a method for creating a "trimmed" copy of the has with only the required parameters would also be OK.

You should write as -
Query = "INSERT INTO t (x,y,z) VALUES (?,?,?)"
hash = {"aval" => "1", "bval" => "2", "cval" => "3"}
db.execute(Query, hash.values_at("aval", "bval", "cval" ))
Read this execute( sql, *bind_vars ) {|row| ...} documentation.

Related

How to use raw sql query string that is created dynamically?

I've seen similar posts here, however they're for older Laravel versions, and also my query string is created dynamically.
I get an array of arrays that represent the values I need to use when I construct the sql query string. For example:
[
["a" => "a1", "b" => "b1", "c" => "c1"],
["a" => "a2", "b" => "b2", "c" => "c2", "d" => "d2"]
]
Then I need to create some complex query that's impossible to write with Laravel's query builder and uses the dynamic data from above:
SELECT
...
WHERE (a="a1", b="b1", c="c1")
OR WHERE (a="a2", b="b2", c="c2", d="d2")
...
From older posts I've seen here, it was mentioned I can use
$result = DB::select($query_string):
Or even with DB::statement.
But, I'm not sure it's still a good way in Laravel 8 and above because it's not in the docs.
But even if yes, it means I'll put the string as is without taking care of binding the values to prevent sql injection.
So how can I do it in the case?
I would go with Closure and foreach, because you can use array with string keys to define where/orWhere conditions.
$conditions = [
["a" => "a1", "b" => "b1", "c" => "c1"],
["a" => "a2", "b" => "b2", "c" => "c2", "d" => "d2"]
];
DB::table('your_table')->where(function($query) use ($conditions) {
foreach($conditions as $condition) {
$query->orWhere($condition);
}
})->selectRaw($query_string)->get();
If you really need to go with raw SQL, just add the raw functions like orderByRaw(), groupByRaw, etc... https://laravel.com/api/9.x/Illuminate/Database/Query/Builder.html
And about sql injection, you need to validate your data. https://laravel.com/docs/9.x/validation

Select specific field in MongoDB using ruby then pass the value to a variable

I'm working on a script that will return value in a specific field and exclude other fields i tried these codes:
name = 'bierc'
puts collection.find({"name"=> name},{:fields => { "_id" => 0}}).to_a
and
name = 'bierc'
collection.find("name" => name,"_id" => 0).each{|row| puts row.inspect}
These two returns
{"_id"=>BSON::ObjectId('55f0d965fcd4fe1c659cf472'), "name"=>"bierc", "song"=>"testsong"}
I want to select name only and exclude the song and especially the _id then will work on to pass the value of name field to a variable.
The option is not fields but projection. You do need _id => 0 but then 1 for any field or fields you do want to select should exclude the others.
collection.find("name" => name, projection: => { "_id" => 0, "name" => 1}})

Ruby put in order columns when creating CSV document from Mongoid

I need to create CSV document from database. So I want to organise columns in particular order and I have template of this order and this template stored as array of headers
header = ["header1", "header2", "header3", "header4", "header5"]
record = [{"header4" =>"value4"}, {"header3" =>"value3"}, {"header5"=>"value5"}, {"header1"=>"value1"}, {"header2"=>"value2"}]
I need to get array like tis
record = [{"header1" =>"value1"}, {"header2" =>"value2"}, {"header3"=>"value3"}, {"header4"=>"value4"}, {"header5"=>"value5"}]
but when I doing
csv<< mymodel.attributes.values.sort_by! { |h| header.index(h.keys[0])
It does not work
When you call mymodel.attributes, you get a Hash back which maps attributes names (as strings) to their values. If your attribute names are header1 through header5 then mymodel.attributes will be something like this:
{
'header1' => 'value1',
'header2' => 'value2',
'header3' => 'value3',
'header4' => 'value4',
'header5' => 'value5'
}
Of course, the order depends on how things come out of MongoDB. The easiest way to extract a bunch of values from a Hash in a specified order is to use values_at:
mymodel.attributes.values_at(*header)

How can i get element in string by Linq

I need some help from Everyone
I have a string: "123456"
how can i get seperately "1", "2", "3", "4", "5", "6" by using Linq?
Tks a lot.
var str = "123456";
var digits = str.Select(c => c.ToString()).ToArray();
"123456".First()
Also, you have the option to include a predicate function. For example,
"123456".First(n => n > '1')
But you may consider using the foreach statement instead. I'm not sure if that is considered part of LINQ though.
You could use this if you want it as a LINQ query:
IEnumerable<string> query =
from c in "123456"
select c.ToString();
If you're happy to have an enumerable of characters you could just do this:
IEnumerable<char> query =
from c in "123456"
select c;

Ruby Nested Hash with Composite Unique Keys

Given a comma separated CSV file in the following format:
Day,User,Requests,Page Views,Browse Time,Total Bytes,Bytes Received,Bytes Sent
"Jul 25, 2012","abc123",3,0,0,13855,3287,10568
"Jul 25, 2012","abc230",1,0,0,1192,331,861
"Jul 25, 2012",,7,0,0,10990,2288,8702
"Jul 24, 2012","123456",3,0,0,3530,770,2760
"Jul 24, 2012","abc123",19,1,30,85879,67791,18088
I wanted to drop the entire dataset (1000 users over 30 days = 30,000 records) into a hash such that Key 1 may be a duplicate key, key 2 may be a duplicate key, but Key 1 & 2 will be unique together.
Example using line 1 above:
report_hash = "Jul 25, 2012" => "abc123" => {"PageRequest" => 3, "PageViews" => 0, "BrowseTime" => 0, "TotalBytes" => 13855, "BytesReceived" => 3287, "BytesSent" => 10568}
def hashing(file)
#read the CSV file into an Array
report_arr = CSV.read(file)
#drop the header row
report_arr.drop(1)
#Create an empty hash to save the data to
report_hash = {}
#for each row in the array,
#if the first element in the array is not a key in the hash, make one
report_arr.each{|row|
if report_hash[row[0]].nil?
report_hash[row[0]] = Hash.new
#If the key exists, does the 2nd key exist? if not, make one
elsif report_hash[row[0]][row[1]].nil?
report_hash[row[0]][row[1]] = Hash.new
end
#throw all the other data into the 2-key hash
report_hash[row[0]][row[1]] = {"PageRequest" => row[2].to_i, "PageViews" => row[3].to_i, "BrowseTime" => row[4].to_i, "TotalBytes" => row[5].to_i, "BytesReceived" => row[6].to_i, "BytesSent" => row[7].to_i}
}
return report_hash
end
I spent several hours learning hashes and associated content to get this far, but feel like there is a much more efficient method to do this. Any suggestions on the proper/more efficient way of creating a nested hash with the first two keys being the first two elements of the array such that they create a "composite" unique key?
You could use the array [day, user] as the hash key.
report_hash = {
["Jul 25, 2012","abc123"] =>
{
"PageRequest" => 3,
"PageViews" => 0,
"BrowseTime" => 0,
"TotalBytes" => 13855,
"BytesReceived" => 3287,
"BytesSent" => 10568
}
}
You just have to make sure the date and user always appear the same. If your date (for example) appears in a different format sometimes, you'll have to normalize it before using it to read or write the hash.
A similar way would be to convert the day + user into a string, using some delimiter between them. But you have to be more careful that the delimiter doesn't appear in the day or the user.
EDIT:
Also make sure you don't modify the hash keys. Using arrays as keys makes this a very easy mistake to make. If you really wanted to, you could modify a copy using dup, like this:
new_key = report_hash.keys.first.dup
new_key[1] = 'another_user'

Resources