I have a synonym statement:
CREATE OR REPLACE SYNONYM sample-table-name FOR master.sample-table-name
I want to execute this by using R language using RJDBC library. I've tried different functions including dbGetQuery function etc. But it is not able to execute this statement.
Could someone please advise on how to execute these statements in R.
I would expect that using dbExecute() should work. Failing that, dbSendStatement() should almost certainly work, as it seems to be intended for that sort of DDL.
The docs on dbGetQuery say:
This method is for SELECT queries only
To look at the functions that are available to you, it can be helpful to do something like ls('package:DBI'). Per the docs:
dbExecute:
Executes a statement and returns the number of rows affected.
dbExecute() comes with a default implementation (which should work
with most backends) that calls dbSendStatement(), then
dbGetRowsAffected(), ensuring that the result is always free-d by
dbClearResult().
dbSendStatement:
The dbSendStatement() method only submits and synchronously executes
the SQL data manipulation statement (e.g., UPDATE, DELETE, INSERT
INTO, DROP TABLE, ...) to the database engine. To query the number of
affected rows, call dbGetRowsAffected() on the returned result object.
You must also call dbClearResult() after that. For interactive use,
you should almost always prefer dbExecute().
EDIT: Those methods will likely work for other implementations of DBI, and perhaps for RJDBC in the future. In any case, it looks like they have implemented dbSendStatement() using dbSendQuery(), so they will not work for this purpose.
In the RJDBC framework, dbSendUpdate() is what you want.
dbSendQuery and dbSendUpdate submit a SQL query to the database. The
difference between the two is only that dbSendUpdate is used with DBML
queries and thus doesn't return any result set.
Confirmed using a similar query on another DBMS:
dbSendStatement(conn,'SET search_path=public;')
#Error in .verify.JDBC.result(r, "Unable to retrieve JDBC result set for ", :
#Unable to retrieve JDBC result set for SET search_path=public; (No results were returned by the query.)
traceback()
#7: stop(..., " (", .jcall(x, "S", "getMessage"), ")")
#6: .verify.JDBC.result(r, "Unable to retrieve JDBC result set for ",
# statement)
#5: .local(conn, statement, ...)
#4: dbSendQuery(conn, statement, ...)
#3: dbSendQuery(conn, statement, ...) ## this is the problem
#2: dbSendStatement(conn, "SET search_path=public;")
#1: dbSendStatement(conn, "SET search_path=public;")
dbSendUpdate(conn, 'SET search_path=public;')
# successful
dbCommit(conn)
# persist the change past the current session (RJDBC seems to give you transaction control here)
Related
I want to print the sql syntax created with DBI::dbBind while creating safe parametrized query:
conn <- #create connection
stmt <- "select * from dbo.mytable where mycolumn = ?"
params = list("myvalue")
query <- DBI::dbSendQuery(conn, stmt)
DBI::dbBind(query, params) # how print created sql syntax?
in the last line the sql syntax is created. How to view it?
I'll formalize my comment into an answer.
"Binding" does not change the query, it merely "augments" a query with objects that are treated solely as data, vice intermingled with code.
The latter intermingling can be problematic for a few reasons:
Malevolent code deploying "SQL Injection" (https://xkcd.com/327/, and a wiki explanation). In short, it takes advantage of closing out a quoted string or literal and executing SQL code directly, perhaps to delete or modify data, perhaps to extract data.
Innocently enough, if the "data" you add to the query contains quotes that are not escaped properly, you could inadvertently perform your own SQL injection, though perhaps less likely to do as "Bad Things" as #1 would do.
Optimization of SQL code. Most DBMSes will analyze and optimize a SQL query so that it performs better, takes advantage of keys, etc. They often remember queries, so that a repeated query does not need to be re-analyzed, saving time. If you intermingle data/parameters in with the raw SQL query text, then when you change one thing about it (even just one digit in a parameter), the DBMS will likely need to re-analyze the query. Inefficient.
There are functions that facilitate escaping or quoting literals and strings, and if you feel you must put literals in your SQL query, then I urge you to use them. These include (but are not limited to) DBI::dbQuoteString, DBI::dbQuoteLiteral, and DBI::dbQuoteIdentifier.
Another such function is glue::glue_sql, which handles correct quoting/escaping of literals and identifiers, to "make[s] constructing SQL statements safe and easy" (quoted from the github repo). This is "just" string interpolation, so while it should protect you just fine against #1 and #2 above, it does not necessarily permit/encourage #3.
(It only takes one mis-quoting to remind you which is used where for your particular DBMS.)
For the record, binding is rather simple, as provided in its documentation:
iris_result <- dbSendQuery(con, "SELECT * FROM iris WHERE [Petal.Width] > ?")
dbBind(iris_result, list(2.3))
results <- dbFetch(iris_result)
If you want, you can re-use the same res (at least in some DBMSes, not tested on all), as in
# same iris_result as above
dbBind(iris_result, list(2.5))
dbFetch(iris_result)
dbBind(iris_result, list(3))
dbFetch(iris_result)
dbBind(iris_result, list(3.2))
dbFetch(iris_result)
As many times as you need, ultimately finishing with
DBI::dbClearResult(iris_result)
I am able to read data. However, when writing data to Teradata database, I get the following error:
Error in .verify.JDBC.result(s, "Unable to create JDBC prepared
statement ", :
Unable to create JDBC prepared statement INSERT INTO
dl_nbu.alex_test2 VALUES(?,?) ([Teradata Database]
[TeraJDBC 16.10.00.07] [Error 3932] [SQLState 25000] Only an ET or
null statement is legal after a DDL Statement.)
Here is my code:
dbWriteTable(tdConnection, "dl_nbu.alex_test2", all_files4)
Hard to give an answer without details. But check the RJDBC help page:
Due to the fact that JDBC can talk to a wide variety of databases, the SQL dialect understood by the database is not known in advance. Therefore the RJDBC implementation tries to adhere to the SQL92 standard, but not all databases are compliant. This affects mainly functions such as dbWriteTable that have to automatically generate SQL code. One major ability is the support for quoted identifiers. The SQL92 standard uses double-quotes, but many database engines either don’t support it or use other character. The
identifier.quote parameter allows you to set the proper quote character for the database used. For example MySQL would require identifier.quote="`". If set to NA, the ability to quote identifiers is disabled, which poses restrictions on the names that can be used for tables and fields. Other functionality is not affected.
Try this and see what happens:
allfiles4 -> allFilesFour
dbWriteTable(tdConnection, "testTwo", allFilesFour)
If works, then the problem is in the quote identifier. Change the line where you make the connection to something like:
tdConnection <- dbConnect( JDBC( identifier.quote = "`" ), ...
Check this post: Do different databases use different name quote?
I'm using RJDBC to connect to a local database. This allows me to make SELECT queries easily using dbGetQuery, and CREATE TABLE using dbWriteTable.
However, I cannot figure out a method to DROP TABLE or DELETE or SELECT INTO directly from my R console. These things work when I do it directly in SQL Developer, but not when I pass the query onto the database from R.
How do I perform database record manipulations which are not SELECT statements using R?
I'd try using a different type instead.
dbGetQuery bases itself on finding and iterating over the DB rather than manipulating it's records.
Similar questions were asked before;
I couldn't find a nice R example, but if it helps, A nice java example could be found here:
EDIT:
I found the type I was talking about! Took me a while, anyhow - sqlQuery allows you to run pretty much any query, that is - a change in the DB records. Example I modified from this source:
res <- sqlQuery(con1,"DELETE TABLE TESTDATA", errors=FALSE)
# res will now hold the result of the query.
# -1 means error, otherwise iteration is sucessful, and it will hold the number of rows affected.
if (res == -1){ #if something messed up
cat ("An error has occurred.\n")
msg <- odbcGetErrMsg(con1) #Use your connection for this.
print (msg)
} else {
cat ("Table was deleted successfully.\n")
}
EDIT 2:
I got it confused with RODBC, however there's no reason to worry, since I found the RJDBC alternative as well! It's called, dbSendUpdate. Example:
# Assuming you have the connection saved as conn; these example shows how to use dbSendUpdate to create tables and insert values.
# You could use it with every non-selective query, that is, which manipulates the record (update,delete,insert,drop etc.)
# create table, with dbSendUpdate:
dbSendUpdate(conn, "CREATE TABLE foo(a INT,b VARCHAR(100))")
# insert value, bind parameters to placeholders in statement:
dbSendUpdate(conn, "INSERT INTO foo VALUES(?,?)", 42, "bar")
# feel free to modify the query itself, these are just example values.
this is similar to another answered question here
basically dbGetQuery() as it name implies is used to send queries and recive their result.
if you want to send a general statement to the db like 'drop table' etc.
you can use:
dbSendUpdate(connection_object, "drop table table_name")
The worst aspect of the Interactive Report (IR) is that you cannot create it using a PL/SQL returning SQL statement. I have gotten around this using two methods:
1) APEX_COLLECTION.CREATE_COLLECTION in the Before Header Process, which takes a SQL statement (that is constructed in PL/SQL in the process), and have the IR's source be select c001 alias1, c002 alias2 ... from apex_collections a where collection_name = '...'
2) Make a badass pipeline function with a parameter list as long as you need and then have the IR's source be select * from table(package_name.pipelined_function_name(:P1_parameter1, :P1_Parameter2))
Is there a performance difference? I originally used the first method but then ran into an occurrence where it was giving me a bug so I tried the pipelined function and found I just liked it better and have tended to use them ever since unless it was inappropriate to do so (namely when there is a large number of items to be passed to the parameter).
First method gives you opportunity to cache data by re-creating the collection only when you need it. Using n00X and d00X columns will give you some additional performance and right column types for the report definition. You can also create a view based on that collection with type casting and column aliases to add more convenience:
create or replace view apx_my_report
as
select n001 id, c001 data, d001 some_date
from apex_collections
where collection_name = 'MY_REPORT'
/
In that case you report source will be like that:
select id, data, some_date from apx_my_report
/
On the other hand, when you need to execute an ad-hoc query every time when page is rendered, it leads to the unavoidable re-creation of a such collection, therefore the performance goes down because of unwanted transaction maintaining: undo, redo etc.
So, it depends.
delete N.* from Tbl_Nodes N, Data_Tree DT WHERE N.Part = DT.Part
for this command I am getting following error.
System.Data.SQLite.SQLiteException: SQLite error near "N": syntax error
Above command works fine for MSAccess.
Is there any alternative to use table shortcut in Sqlite?
The DELETE statement operates on a single table and does not use a table alias. Therefore, your FROM clause must read FROM Tbl_Nodes.
You're probably looking for:
delete from Tbl_Nodes WHERE Part IN (SELECT Part FROM Data_Tree)
Note that this will remove all nodes from Tbl_Nodes that have a corresponding Part value in Data_Tree but does not remove any records from Data_Tree itself.
While SQL varies somewhat among vendors, as a general principle it's a mistake to learn SQL from MS Access and try to apply it to other products. MS Access features some very non-standard constructions.
Using an alias for the table?
FROM table AS t1
You're missing a bit of your SQL statement there I guess but does it not work if you just say:
delete N from Tbl_Nodes N, Data_tree DT WHERE...(rest of statement)
I've just removed the .*