As far as i have seen the documentation on some statements dynamic operations are not allowed like if i want to execute the statement
res = conn.exec_params('CREATE DATABASE $1',[dbname])
i am getting this error
Error: ERROR: syntax error at or near "$1"
LINE 1: CREATE DATABASE $1
while if i use select statement SELECT * FROM pg_database WHERE datname = $1 this statement is successful.
While the above issue was not there with dbd/pg gem but it seems it hasnt been released from past 2010 which translate the dynamic paramters into native pg and with latest ruby and pg gem dbd/pg is not working.
My question is do we have any way with native PG gem to perform dynamic replacement of variables with create database, insert into like statements. OR is there any alternative for dbd/pg which offers same functionality?
Placeholders (i.e. $1, $2, ...) are for values. A database name (or table name, column name, ...) is an identifier. This is similar to the difference between a variable name and the value the variable holds in Ruby.
If you need to dynamically insert an identifier in some SQL then you need to use string interpolation and the special purpose quote_ident method to make sure you quote it properly. So something more like this:
db_name = conn.quote_ident(db_name)
res = conn.exec("CREATE DATABASE #{db_name}")
Related
Notes: Using Ruby 2.4, oci8 / oracle enhanced adapter.
I was using sqlplus to execute some DDL / DML I have. Basically this:
system "echo / | sqlplus #{db.username}/\"#{db.password}\"##{db.host}:#{db.port}/#{db.sid} #\"#{file_to_execute}\" > #{#SQLOUT_LOG}"
I want to move away from using sqlplus and use active record instead. So I got this working:
ActiveRecord::Base.connection.execute(IO.read("#{file_path}"))
And that does basically the same thing, except: I cannot access the 'script output' that I got from SQLplus (or even SQLDeveloper). This 'execute' function returns table rows, which I usually don't care about or need.
I just want a string of the output result of the script after I run it. Example:
Procedure MYPROCEDURE compiled
3 rows inserted.
etc....
puts ActiveRecord::Base.connection.execute(IO.read("#{file_path}"))
I think I've determined that there is no way to get the information I'm trying to get using ActiveRecord, and will try to look into other options or keep using sqlplus.
I am trying to convert SQL code to Seqel to run it from my script. How do I convert this:
select code, count(1) as total
from school_districts
group by code order by total desc;
into Sequel? Or, is there a way to pass raw SQL to Sequel? Also the school_districts will be interpolated #{table_name}.
DB[:school_districts].select(:code).group_and_count(:code).reverse_order(:count)
is a Sequel way of executing that query. I did not however alias the count column, but I hope you can do with this.
Even though working in Sequel is preferable as it allows you to change DBMs without changing your code I would prefer you use the fetch method.
You can do it a couple ways:
Use []:
DB["your sql string"]
Use fetch:
DB.fetch("your sql string")
I am testing this perl script which basically call procedure and run DELETE on 2 tables.
Questions:
Is there any issue with the procedure or calling procedure in perl?
Can I use 2 deletes in single procedure?
Procedure delete (v_db_id in number)
IS BEGIN
DELETE from TAB1
where db_id = v_db_id;
DELETE from TAB2
where db_id = v_db_id;
END delete;
PERL Script:
sub getdelete {
my $dbID = shift
my $rs;
my $SQL;
$SQL = q{delete (?)};
$rs = executeQuery($SQL,$dbID);
$rs -> fetchrow();
$rs -> finish();
}
PERL Script calling subroutine getdelete as below:
&getdelete ($dbID);
Error:
DBD::Oracle::st execute failed: ORA-00900: invalid SQL statement (DBD Error: OCIStmtExecute)[for statement "delete"]
DELETE doesn't takes an expression that results in a table id; it takes a table id literal. As such, you can't use replaceable parameters. You need to construct the table id literal, which $dbh->quote_identifier can do.
my $sql = 'DELETE '.$dbh->quote_identifier($dbID);
$dbh->do($sql);
You are using a module that wraps DBI in a very poor way1. I have no way of knowing if it'll give access to the database handle or to the handle's quote_identifier method, but at least now you know what to look for.
Notes:
There are three ways to wrap DBI that make sense:
To add functions or override some minor aspect of existing functions.
For example, DBI database statements don't have the selectrow_* methods founds on database handles. Adding these without restricting access to the rest of DBI is perfectly fine.
To provide a higher level abstraction of a database, such as an ORM like DBIx::Class. These are massive systems with thousands if not tens of thousands of lines.
If your wrapper provide a new database interface and its code fits on two screens, it's doing something wrong.
To centralise all DB code by providing application-specific functions like create_user, fetch_daily_report_data, etc. SQL isn't passed
If your wrapper attempts to this but provides functions that expect SQL, it's doing something wrong.
What doesn't make sense is to attempt to simplify DBI, and this appears to be what your wrapper does. DBI actually provides a very simple interface. Any attempts to simplify it is bound to leave out something critical.
I am a total newbie. I have a database with a table called OUTPUTS where all columns are of type integer. I am trying to insert a row into OUTPUTS with the following ruby script:
require 'rubygems'
require 'sqlite3'
...
db=SQLite3::Database.new("development.sqlite3")
db.execute( "INSERT into OUTPUTS (user_id,eac,pac,vac,iac,epv,ppv,vpv) VALUES (10,#eac,#pac,#vac,#iac,#epv,#ppv,#vpv);" )
Upon running this script, I do get a new row and the user_id column has a 10 in it as expected, but the rest of the columns are empty even though I verified that all of the variables (#eac, #pac, etc) do indeed contain values. What is wrong with my syntax?
You're sending the names of the variables to sqlite, not their values. This is what you want:
db.execute( "INSERT into OUTPUTS (user_id,eac,pac,vac,iac,epv,ppv,vpv)
VALUES (10,#{#eac},#{#pac},#{#vac},#{#iac},#{#epv},#{#ppv},#{#vpv});" )
But even better would be to use variable binding like this:
db.execute( "INSERT into OUTPUTS (user_id,eac,pac,vac,iac,epv,ppv,vpv)
VALUES (10,?,?,?,?,?,?,?)",
#eac,#pac,#vac,#iac,#epv,#ppv,#vpv)
(I may have messed up my count there).
Check out How do I use placeholders in an SQL statement? for some more details.
When trying to enter a SQL query with parameters using the Oracle OLE DB provider I get the following error:
Parameters cannot be extracted from the SQL command. The provider might not help to parse parameter information from the command. In that case, use the "SQL command from variable" access mode, in which the entire SQL command is stored in a variable.
ADDITIONAL INFORMATION:
Provider cannot derive parameter information and SetParameterInfo has not been called. (Microsoft OLE DB Provider for Oracle)
I have tried following the suggestion here but don't quite understand what is required:Parameterized queries against Oracle
Any ideas?
To expand on the link given in the question:
Create a package variable
Double click on the package variable name. (This allows you to access the properties of the variable)
Set the property 'EvaluateAsExpression' to true
Enter the query in the expression builder.
Set the OLE DB source query to SQL Command from Variable
The expression builder can dynamically create expressions using variable to create 'parametised queries'.
So the following 'normal' query:
select * from book where book.BOOK_ID = ?
Can be written in the expression builder as:
"select * from book where book.BOOK_ID = " + #[User::BookID]
You can then do null handling and data conversion using the expression builder.
If You use Data Flow Task and use OLE DB Source, and you need parameterize your Query :
Create Variable to save "Full" of Query statement : Right Click on blank area outside the package - and Click Variables :
Click Add Variables on Variables Window :
Make the name is SQL_DTFLOW_FULL or something that can you understand easily. The variable data type is STRING
Create Variable(s) to save your parameter(s).
i.e, the full of Query stamements is :
SELECT * FROM BOOK WHERE BOOK_ID = #BookID --#BookID is SQL Parameter
at the sample above, I have just one parameter : #BookID, so I need to create one variable to save my parameter. Add more variables depends on your Queries.
Give it name SQL_DTFLOW_BOOKID
The variable data type is STRING
So, you need make your SSIS neat, and the variables is sorted in understandable parts.
Try to make the variable name is SQL_{TASK NAME}_{VariableName}
Make Expression for SQL_DTFLOW_FULL variable, click on number 1, and start fill number 2. Make Your SQL Statements to be a correct SQL Statement using string block. String block usually using "Double Quote" at the beginning and the end. Concat the variables with the string block.
Click evaluate Expression, to showing result, to make sure your query is correct, copy-paste the Query result at SSMS.
Make sure by yourself that the variables is free from SQL Injection using your own logic. (Use your developer instinct)
Open the Data Flow Task, open the OLE DB Source Editor by double click the item.
Select the Data Access Mode : SQL Command From Variable
Select the Variable Name : SQL_DTFLOW_FULL
Click Preview to make sure it works.
That is all, my way to prevent this SSIS failure case. Since I use this way, I never got that problem, you know, SSIS something is weird.
To change the variable value, set it before Data Flow Task, the SQL Result of SQL_DTFLOW_FULL variable will changed every you change your variable value.
In my case the issue was that i had comments within the sql in the normal form of /* */ and i also had column aliases as "Column name" instead of [Column Name].
Once i removed them it works.
Also try to have your parameter ? statement within the WHERE clause and not within the JOINS, that was part of the issue too.