Mixing single and double quotes in the R paste function? - mysql

This seems ridiculous, but I just can't get this right - any help much appreciated please!
Basically: I'm using RMySQL to do some simple SQL, in order to get my head around how SQL works. I'd like to chain together a few SQL select queries, as a simple example. This is covered in the RMySQL PDF - but the example therein seems to be the incorrect syntax (http://cran.r-project.org/web/packages/RMySQL/RMySQL.pdf , page 3, example 6).
If I have three queries, say like this:
q1 <- "SELECT db.table FROM table WHERE stuff = 'blah' "
q2 <- "SELECT db.other_table FROM other_table WHERE stuff = 'different blah' "
q3 <- "SELECT db.table2 FROM table2 WHERE table2 = 1000"
and try to paste them as follows:
script <- paste(q1, q2, q3, sep=";")
the result is
> script
[1] "SELECT db.table FROM table WHERE stuff = 'blah' ;SELECT fb.other_table FROM
other_table WHERE stuff = 'different blah' ;SELECT db.table2 FROM table2 WHERE table2 =
'1000'
and so invoking dbSendQuery clearly fails.
I've tried \", but this also doesn't work:
q1 <- "SELECT db.table FROM table WHERE stuff = 'blah' \" "
q2 <- "SELECT db.other_table FROM other_table WHERE stuff = 'different blah' \""
q3 <- "SELECT db.table2 FROM table2 WHERE table2 = 1000 \" "
script <- paste(q1, q2, q3, sep=";")
> script
[1] "SELECT db.table FROM table WHERE stuff = 'blah' \" ; ;SELECT db.other_table FROM
other_table WHERE stuff = 'different blah' \";SELECT db.table2 FROM table2 WHERE table2
= 1000 \" "
Can anyone please point out what I'm doing wrong?
EDIT: just for clarification, executing this via RMySQL as follows:
my.queries <- dbGetQuery(my.con, script, client.flag = CLIENT_MULTI_STATEMENTS)
as per the RMySQL manual, I get
RS-DBI driver: (could not run statement: You have an error in your SQL syntax;
Presumably, this is because the result of the paste function should be:
"SELECT db.table FROM table WHERE stuff = 'blah'" ;"SELECT fb.other_table FROM
other_table WHERE stuff = 'different blah'" ;"SELECT db.table2 FROM table2 WHERE table2
= '1000'"
Each of the individual queries works just fine, so I'm assuming that it's my paste command that's causing the issue.
EDIT: to simplify this: suppose I have two strings, as follows:
t1 <- "the 'stuff'"
t2 <- "more 'stuff'"
paste(t1, t2, sep=";")
[1] "the 'stuff' ; more 'stuff' "
what I'd like is for the result of the paste command to be "the 'stuff'";"more 'stuff'".

You have to pass the argument client.flag = CLIENT_MULTI_STATEMENTS to the function dbConnection, not to dgGetQuery.
Then, your first approach should work:
q1 <- "SELECT db.table FROM table WHERE stuff = 'blah' "
q2 <- "SELECT db.other_table FROM other_table WHERE stuff = 'different blah' "
q3 <- "SELECT db.table2 FROM table2 WHERE table2 = 1000"
script <- paste(q1, q2, q3, sep=";")

Related

Extract DB name and table name from snowflake query using snowsql

Insert into D.d
Select * from A.a join B.b on
A.a.a1=B.b.b1
Join C.c on C.c.c1=B.b.b1
I have complex statements for which i need to extract source db name ( in above statement source DB are A,B,C and source tables are a,b,c &Target Db is D and target table is d)
Need output like
SourceDB SourceTbl TargetDB Targettbl
A,B,C a,b,c D d
Or we can get values in json format as well for each field.. Also this needs to accomodate for update and delete statements as well. Please assist
Thanks
You can use the SQLPARSE to parse the statement. I am providing a code below which is not optimally and efficiently written, but it has the logic to get the information
import sqlparse
raw = 'Insert into D.d ' \
'Select * from A.a join B.b on ' \
'A.a.a1=B.b.b1 Join C.c on C.c.c1=B.b.b1;'
parsed = sqlparse.parse(raw)[0]
tgt_switch = "N"
src_switch = "N"
src_table=[]
tgt_table= ""
for items in parsed.tokens:
#print(items,items.ttype)
if str(items) == "into":
tgt_switch ="Y"
if tgt_switch == "Y" and items.ttype is None:
tgt_switch = "N"
tgt_table = items
if str(items).lower() == "from" or str(items).lower() == "join":
src_switch = "Y"
if src_switch == "Y" and items.ttype is None:
src_switch = "N"
src_table.append(str(items))
target_db = str(tgt_table).split(".")[0]
target_tbl = str(tgt_table).split(".")[1]
print("Target DB is {} and Target table is {}".format(target_db,target_tbl))
for obj in src_table:
src_db = str(obj).split(".")[0]
src_tbl = str(obj).split(".")[1]
print("Source DB is {} and Source table is {}".format(src_db, src_tbl))
Snowflake does not offer any SQL statement parsing support. You can hack at it with regex'es, of course, or use any of the tools on the market.
If this query ran, and ran successfully, you can use ACCESS_HISTORY view https://docs.snowflake.com/en/sql-reference/account-usage/access_history.html to see which tables (A.a, B.b, C.c, D.d) and columns (A.a.a1, B.b.b1, C.c.c1, D.d.d1) it accessed and how (read or write).

Combining input from shiny widgets and MySQL queries with less code

I have an application that allows users to query MySQL database using input widgets on a shiny app. The queries involve joining tables too. The code becomes too long when employing IF ...ELSE statements to determine if a widget is empty or has some user input like in the code below.
Sample MySQL data can be created as below:
CREATE TABLE quoteauthors (
FirstName VARCHAR(255) ,
LastName VARCHAR(255) ,
authorID VARCHAR(255)
);
CREATE TABLE quotes (
quote VARCHAR(255) ,
authorID VARCHAR(255)
);
INSERT INTO quoteauthors
VALUES ('Albert', 'Einstein', 'a1'),
('Stephen', 'Hawking', 'a2'),
('Isaac', 'Newton', 'a3');
INSERT INTO quotes
VALUES ('Unthinking respect for authority is the greatest enemy of truth.', 'a1'),
('In the middle of difficulty lies opportunity.', 'a1'),
('Intelligence is the ability to adapt to change.', 'a2'),
('Science is not only a disciple of reason but, also, one of romance and passion.', 'a2'),
('If I have seen further it is by standing on the shoulders of Giants.', 'a3'),
('I can calculate the motion of heavenly bodies but not the madness of people', 'a3');
Sample shiny app is as below:
library(shiny)
library(shinydashboard)
library(DBI)
library(RMySQL)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("QUOTE Search", tabName = "Tabs", icon = icon("object-ungroup"))
)
),
dashboardBody(
tabItem(tabName = "Tabs",
fluidRow(
column(width=3,
box(
title="Search ",
solidHeader=TRUE,
collapsible=TRUE,
width=NULL,
textInput("quoteSearch1", " Search Term 1 ", '', placeholder = "Type search term"),
radioButtons("combi", "Logical Operator to Combine Terms:",
c(
"AND" = "AND",
"OR" = "OR"
), inline = TRUE),
textInput("quoteSearch2", " Search Term 2 ", '', placeholder = "Type search term"),
selectInput("authorchoice", "Select AUTHOR", selected = NULL, multiple = T,
choices=c('Albert','Stephen','Isaac')),
submitButton("Search")
)
),
column( width=9,
tabBox(
width="100%",
tabPanel("Search Results",
htmlOutput("quotesearchdetails")
)))))))
server <- function(input, output) {
output$quotesearchdetails <-renderUI({
if(input$quoteSearch1!=""){
con <- dbConnect(MySQL(),
user='XXXXXXXXXXX',
port = 3306, password='XXXXXXXXXXX',
dbname='XXXXXXXXXXX',
host='XXXXXXXXXXX')
dbSendQuery(con, "SET NAMES utf8mb4;")
dbSendQuery(con, "SET CHARACTER SET utf8mb4;")
dbSendQuery(con, "SET character_set_connection=utf8mb4;")
on.exit(dbDisconnect(con), add = TRUE)
quotedetails <- reactive({
if (input$authorchoice == ""){
if (input$quoteSearch2 == ""){
dbGetQuery(con, statement =
paste0(" SELECT q.quote, a.FirstName, a.LastName
FROM quotes q
JOIN quoteauthors a
ON (q.authorID = a.authorID)
WHERE (q.quote LIKE '%",input$quoteSearch1,"%') "))
}else{
if (input$combi == "AND"){
dbGetQuery(con, statement =
paste0("
SELECT q.quote, a.FirstName, a.LastName
FROM quotes q
JOIN quoteauthors a
ON (q.authorID = a.authorID)
WHERE (q.quote LIKE '%",input$quoteSearch1,"%' AND
q.quote LIKE '%",input$quoteSearch2,"%')"))
}else{
dbGetQuery(con, statement =
paste0("
SELECT q.quote, a.FirstName, a.LastName
FROM quotes q
JOIN quoteauthors a
ON (q.authorID = a.authorID)
WHERE (q.quote LIKE '%",input$quoteSearch1,"%'
OR q.quote LIKE '%",input$quoteSearch2,"%')"))
}
}
}else{
if (input$quoteSearch2 == ""){
dbGetQuery(con, statement =
paste0("
SELECT q.quote, a.FirstName, a.LastName
FROM quotes q
JOIN quoteauthors a
ON (q.authorID = a.authorID)
WHERE (q.quote LIKE
'%",input$quoteSearch1,"%'
AND a.FirstName LIKE '%",input$authorchoice,"%') "))
}else {
if (input$combi == "AND"){
dbGetQuery(con, statement =
paste0("
SELECT q.quote, a.FirstName, a.LastName
FROM quotes q
JOIN quoteauthors a
ON (q.authorID = a.authorID)
WHERE (q.quote LIKE '%",input$quoteSearch1,"%' AND
q.quote LIKE '%",input$quoteSearch2,"%') AND
a.FirstName LIKE '%",input$authorchoice,"%' "))
}else{
dbGetQuery(con, statement =
paste0("
SELECT q.quote, a.FirstName, a.LastName
FROM quotes q
JOIN quoteauthors a
ON (q.authorID = a.authorID)
WHERE (q.quote LIKE '%",input$quoteSearch1,"%' OR
q.quote LIKE '%",input$quoteSearch2,"%')
AND
a.FirstName LIKE '%",input$authorchoice,"%' "))
}
}
}
})
outputed=""
quotedetailsreturned <- quotedetails()
if (dim(quotedetailsreturned)[1] > 0){
for(i in seq(from=1,to=dim(quotedetailsreturned)[1])){
outputed<-paste(outputed,
paste("Author's First name: ",quotedetailsreturned[i,"FirstName"]),
sep="<br/><br/>")
outputed<-paste(outputed,
paste("Author's Last name: ",quotedetailsreturned[i,"LastName"]),
sep="<br/><br/>")
outputed<-paste(outputed,
paste("Quote: ",quotedetailsreturned[i,"quote"]),
sep="<br/><br/>")
}
} else { outputed <-"your search yielded no results."}
HTML(outputed)
}else {
paste("Please input a search term at least in the first field")
}
})
}
shinyApp(ui, server)
I am seeking a solution on how to avoid the repetition and long codes using the IF...ELSE statements in my code. What best programming practices I could use to combine the MySQL queries with user input on various shiny widgets including textInput, radioButtons, selectize/selectInput and so on by considering some inputs can be left empty thus should not be considered in the query.
I would first build the query string only, step-by-step, adding each clause at a step according to the chosen settings. After it has been built, execute the query. Makes the code much shorter and easier to read.

UPDATE SQL Query with joins [duplicate]

Is there a way to use joins in update statements for DB2?
Google has really let me down on this one
This is roughly what I'm trying to achieve (... except obviously working ....)
update file1 inner join file2
on substr(file1.firstfield,10,20) = substr(file2.anotherfield,1,10)
set file1.firstfield = ( 'BIT OF TEXT' concat file2.something )
where file1.firstfield like 'BLAH%'
Cheers
You don't say what platform you're targeting. Referring to tables as files, though, leads me to believe that you're NOT running DB2 on Linux, UNIX or Windows (LUW).
However, if you are on DB2 LUW, see the MERGE statement:
update: note that Db2 for IBM i added MERGE support in late 2010 to v7.1 and higher. Db2 for z/OS also has it.
For your example statement, this would be written as:
merge into file1 a
using (select anotherfield, something from file2) b
on substr(a.firstfield,10,20) = substr(b.anotherfield,1,10)
when matched and a.firstfield like 'BLAH%'
then update set a.firstfield = 'BIT OF TEXT' || b.something;
Please note: For DB2, the third argument of the SUBSTR function is the number of bytes to return, not the ending position. Therefore, SUBSTR(a.firstfield,10,20) returns CHAR(20). However, SUBSTR(b.anotherfield,1,10) returns CHAR(10). I'm not sure if this was done on purpose, but it may affect your comparison.
Joins in update statements are non-standard and not supported by all vendors. What you're trying to do can be accomplished with a sub-select:
update
file1
set
firstfield = (select 'stuff' concat something from file2 where substr(file1.field1, 10, 20) = substr(file2.xxx,1,10) )
where
file1.foo like 'BLAH%'
Try this and then tell me the results:
UPDATE File1 AS B
SET b.campo1 = (SELECT DISTINCT A.campo1
FROM File2 A
INNER JOIN File1
ON A.campo2 = File1.campo2
AND A.campo2 = B.campo2)
Here's a good example of something I just got working:
update cac c
set ga_meth_id = (
select cim.ga_meth_id
from cci ci, ccim cim
where ci.cus_id_key_n = cim.cus_id_key_n
and ci.cus_set_c = cim.cus_set_c
and ci.cus_set_c = c.cus_set_c
and ci.cps_key_n = c.cps_key_n
)
where exists (
select 1
from cci ci2, ccim cim2
where ci2.cus_id_key_n = cim2.cus_id_key_n
and ci2.cus_set_c = cim2.cus_set_c
and ci2.cus_set_c = c.cus_set_c
and ci2.cps_key_n = c.cps_key_n
)
Just to update only the rows that match the conditions, and avoid updating nulls in the other rows:
update table_one set field_1 = 'ACTIVE' where exists
(select 1 from table_two where table_one.customer = table_two.customer);
It works in a DB2/AIX64 9.7.8
Update to the answer https://stackoverflow.com/a/4184237/565525:
if you want multiple columns, that can be achived like this:
update file1
set
(firstfield, secondfield) = (
select 'stuff' concat 'something from file2',
'some secondfield value'
from file2
where substr(file1.field1, 10, 20) = substr(file2.xxx,1,10) )
where
file1.foo like 'BLAH%'
Source: http://www.dbforums.com/db2/1615011-sql-update-using-join-subquery.html#post6257307
for you ask
update file1 f1
set file1.firstfield=
(
select 'BIT OF TEXT' || f2.something
from file2 f2
where substr(f1.firstfield,10,20) = substr(f2.anotherfield,1,10)
)
where exists
(
select * from file2 f2
where substr(f1.firstfield,10,20) = substr(f2.anotherfield,1,10)
)
and f1.firstfield like 'BLAH%'
if join give multiple result you can force update like this
update file1 f1
set file1.firstfield=
(
select 'BIT OF TEXT' || f2.something
from file2 f2
where substr(f1.firstfield,10,20) = substr(f2.anotherfield,1,10)
fetch first rows only
)
where exists
(
select * from file2 f2
where substr(f1.firstfield,10,20) = substr(f2.anotherfield,1,10)
)
and f1.firstfield like 'BLAH%'
template methode
update table1 f1
set (f1.field1, f1.field2, f1.field3, f1.field4)=
(
select f2.field1, f2.field2, f2.field3, 'CONSTVALUE'
from table2 f2
where (f1.key1, f1.key2)=(f2.key1, f2.key2)
)
where exists
(
select * from table2 f2
where (f1.key1, f1.key2)=(f2.key1, f2.key2)
)
The reference documentation for the UPDATE statement on DB2 LUW 9.7 gives the following example:
UPDATE (SELECT EMPNO, SALARY, COMM,
AVG(SALARY) OVER (PARTITION BY WORKDEPT),
AVG(COMM) OVER (PARTITION BY WORKDEPT)
FROM EMPLOYEE E) AS E(EMPNO, SALARY, COMM, AVGSAL, AVGCOMM)
SET (SALARY, COMM) = (AVGSAL, AVGCOMM)
WHERE EMPNO = '000120'
The parentheses after UPDATE can contain a full-select, meaning any valid SELECT statement can go there.
Based on that, I would suggest the following:
UPDATE (
SELECT
f1.firstfield,
f2.anotherfield,
f2.something
FROM file1 f1
WHERE f1.firstfield like 'BLAH%'
INNER JOIN file2 f2
ON substr(f1.firstfield,10,20) = substr(f2.anotherfield,1,10)
)
AS my_files(firstfield, anotherfield, something)
SET
firstfield = ( 'BIT OF TEXT' || something )
Edit: Ian is right. My first instinct was to try subselects instead:
UPDATE file1 f1
SET f1.firstfield = ( 'BIT OF TEXT' || (
SELECT f2.something
FROM file2 f2
WHERE substr(f1.firstfield,10,20) = substr(f2.anotherfield,1,10)
))
WHERE f1.firstfield LIKE 'BLAH%'
AND substr(f1.firstfield,10,20) IN (
SELECT substr(f2.anotherfield,1,10)
FROM file2 f2
)
But I'm not sure if the concatenation would work. It also assumes that there's a 1:1 mapping between the substrings. If there are multiple rows that match, it wouldn't work.
On DB2 it's like that :
UPDATE TABLE
set TABLE.firstfield = ( 'BIT OF TEXT' concat TABLE.something )
where TABLE.firstfield like 'BLAH%'
UPDATE tes_1 a
SET a.nama =
(SELECT b.nama FROM tes_2 b WHERE a.urut = b.urut )
In standard SQL this type of update looks like:
update a
set a.firstfield ='BIT OF TEXT' + b.something
from file1 a
join file2 b
on substr(a.firstfield,10,20) =
substr(b.anotherfield,1,10)
where a.firstfield like 'BLAH%'
With minor syntactic variations this type of thing will work on Oracle or SQL Server and (although I don't have a DB/2 instance to hand to test) will almost certainly work on DB/2.

insert a row of data from a data frame directly to a database in R

I am able to insert a row into a database, value-by-value in R as follows
#connect
conn = odbcDriverConnect("Driver=SQL Server; Server=MyServerName; Database=MyDBName; Uid=IAMTubby; Pwd=abcd;")
#insert
myquery = "insert into MyTableName values('1234','M','6','3');"
res = sqlQuery(conn, myquery)
However, I would like to insert maybe the first row of my data frame directly into sql instead of segregating them into values. How can I do this?
Say, my data frame looks like the following, and is of the same schema as the database
> df[1,]
col1 col2 col3 col4
1 1234 M 6 3
EDIT : I tried sqlSave but my RStudio crashes when I execute the following code. Where am I going wrong?
Table creation code in SQL-Server
#table creation
use DBName
CREATE TABLE Persons
(
col1 varchar(255),
col2 varchar(255),
col3 varchar(255),
);
R glue code
#library
library("RODBC")
#connect
conn = odbcDriverConnect("Driver=SQL Server; Server=MyServer; Database=DBName; Uid=username; Pwd=abcd;")
#inserting a data frame
df = NULL
df$col1 = '1'
df$col2 = '2'
df$col3 = '3'
df = as.data.frame(df)
sqlSave(conn, df[1,], tablename = "Persons", append = TRUE)
OPTION 1: You could create the query dynamically like this:
df = data.frame(col1 = 1234, col2 = "M", col3 = 6, col4 = 3)
myquery = paste0("insert into MyTableName values(", paste0("'", df[1,], "'", collapse = ", "), ");")
This will save the following string in the object myquery:
"insert into MyTableName values('1234', '1', '6', '3');"
OPTION 2:
As #nrussell commented you should also be able to use the sqlSave function in the RODBC package with:
sqlSave(conn, df[1,], tablename = "MyTableName", append = TRUE)

How to do dbGetQuery for loop in R

i have three variables a,b,c (Actually more than 300 variables in my case)
t<-c(a,b,d)
a<-dbGetQuery(con, "SELECT * FROM a")
b<-dbGetQuery(con, "SELECT * FROM b")
d<-dbGetQuery(con, "SELECT * FROM d")
How can I make a loop to request data from MySQL in R? The existing question does not have the explanation on how to write it into the variable names. I need a,b,c in my environment.
Not tested, but something as below should work.
myTables <- c("a","b","c")
res <- lapply(myTables,
function(myTable){
sqlStatement <- paste("select * from",myTable)
dbGetQuery(con, sqlStatement)
})
names(res) <- myTables