2017-08-08 2 views
0

Ich stolperte neulich über diesen Artikel: http://deanattali.com/blog/shiny-persistent-data-storage/#sqlite, und wollte es für mich selbst ausprobieren.Datenspeicherung in Shiny App mit RODBC

Allerdings muss ich RODBC verwenden und das ist nicht in dem Artikel erwähnt.

Zur Zeit habe ich das versucht:

table <- "[shinydatabase].[dbo].[response]" 

fieldsMandatory <- c("name", "favourite_pkg") 

labelMandatory <- function(label) { 
    tagList(
    label, 
    span("*", class = "mandatory_star") 
) 
} 

appCSS <- 
    ".mandatory_star { color: red; }" 


fieldsAll <- c("Name", "favpkg", "used_shiny", "num_years", "os_type") 

shinyApp(
    ui = fluidPage(
    shinyjs::useShinyjs(), 
    shinyjs::inlineCSS(appCSS), 
    titlePanel("Mimicking a Google Form with a Shiny app"), 

    div(
     id = "form", 

     textInput("name", labelMandatory("Name"), ""), 
     textInput("favourite_pkg", labelMandatory("Favourite R package")), 
     checkboxInput("used_shiny", "I've built a Shiny app in R before", FALSE), 
     sliderInput("r_num_years", "Number of years using R", 0, 25, 2, ticks = FALSE), 
     selectInput("os_type", "Operating system used most frequently", 
        c("", "Windows", "Mac", "Linux")), 
     actionButton("submit", "Submit", class = "btn-primary") 
    ) 

), 

    server = function(input, output, session) { 
    observe({ 
     mandatoryFilled <- 
     vapply(fieldsMandatory, 
       function(x) { 
       !is.null(input[[x]]) && input[[x]] != "" 
       }, 
       logical(1)) 
     mandatoryFilled <- all(mandatoryFilled) 
     shinyjs::toggleState(id = "submit", condition = mandatoryFilled) 

    }) 

    formData <- reactive({ 
     data <- sapply(fieldsAll, function(x) input[[x]]) 
    }) 

    saveData <- function(data) { 
     # Connect to the database 
     db<- odbcConnect(".", uid = "uid", pwd = "pwd") 
     # Construct the update query by looping over the data fields 
     query <- sprintf(
     "INSERT INTO [shinydatabase].[dbo].[response] (Name, favpkg, used_shiny, num_years, os_type) VALUES ('%s')", 
     paste(data, collapse = "', '") 
    ) 
     # Submit the update query and disconnect 
     sqlQuery(db, query) 
     odbcClose(db) 
    } 

    loadData <- function() { 
     # Connect to the database 
     odbcChannel<- odbcConnect(".", uid = "uid", pwd = "pwd") 
     # Construct the fetching query 
     query <- sprintf("SELECT * FROM [shinydatabase].[dbo].[response]") 
     # Submit the fetch query and disconnect 
     data <- sqlQuery(db, query) 
     odbcClose(db) 
     data 
    } 

    # action to take when submit button is pressed 
    observeEvent(input$submit, { 
     saveData(formData()) 
    }) 

    } 
) 

Diese im Grunde das gleiche wie in dem Artikel und die Anwendung ausgeführt wird, und keine Fehler zurück in meiner Datenbank, jedoch keine Informationen lesen Tabelle dargestellt.

Wenn ein normaler Einsatz in Anweisung wie folgt vorgehen:

sqlQuery(db, "INSERT INTO [shinydatabase].[dbo].[response] (Name, favpkg, used_shiny, num_years, os_type) VALUES ('a', 'b', 'yes', '2','mac') 

Es funktioniert so weiß ich, dass nicht das Problem ist.

Antwort

1

Ich würde empfehlen, Ihre saveData Funktion neu zu schreiben, um RODBCext zu verwenden. Indem Sie die Abfrage parametrisieren, können Sie klären, wie die endgültige Abfrage aussieht, und vor einer SQL-Injektion schützen.

saveData <- function(data) { 
     # Connect to the database 
     db<- odbcConnect(".", uid = "uid", pwd = "pwd") 
     # make sure the connection is closed even if an error occurs. 
     on.exit(odbcClose(db)) 

     sqlExecute(
     channel = db, 
     query = "INSERT INTO [shinydatabase].[dbo].[response] 
       (Name, favpkg, used_shiny, num_years, os_type) 
       VALUES 
       (?, ?, ?, ?, ?)", 
     data = data 
    ) 
    } 
0

Ich bin die Blog-Methode liefert erstaunt gewünschten Ergebnisse als R c Funktion in die Abfrage als String blutet wörtliche und jeder Wert in jeder Spalte verkettet und als eine Zeile Strings mit eingebetteten Kommas gespeichert. Um zu zeigen, mit zufälligen Buchstabendaten:

sample.seed(111) 
data <- data.frame(col1 = sample(LETTERS, 5), 
        col2 = sample(LETTERS, 5), 
        col3 = sample(LETTERS, 5), 
        col4 = sample(LETTERS, 5), 
        col5 = sample(LETTERS, 5), stringsAsFactors = FALSE) 

query <- sprintf(
    "INSERT INTO [shinydatabase].[dbo].[response] (Name, favpkg, used_shiny, num_years, os_type) VALUES ('%s')", 
    paste(data, collapse = "', '") 
) 

query 
# [1] "INSERT INTO [shinydatabase].[dbo].[response] (Name, favpkg, used_shiny, 
# num_years, os_type) VALUES ('c(\"E\", \"C\", \"I\", \"U\", \"B\")', 
# 'c(\"F\", \"W\", \"R\", \"O\", \"L\")', 'c(\"Q\", \"V\", \"M\", \"T\", \"I\")', 
# 'c(\"Y\", \"V\", \"C\", \"M\", \"O\")', 'c(\"A\", \"V\", \"U\", \"I\", \"D\")')" 

jedoch für spezielle Bedürfnisse zu SQL Server Dialekt auszurichten, Gebäude Werte setzt mit apply Schleife betrachten und verketten dann zu größerem Query-String:

vals <- paste(apply(data, 1, function(d) paste0("('", paste(d, collapse = "', '"), "')")), collapse = ", ") 

query <- sprintf("INSERT INTO [shinydatabase].[dbo].[response] ([Name], favpkg, used_shiny, num_years, os_type) VALUES %s", vals)  
query 
# [1] "INSERT INTO [shinydatabase].[dbo].[response] (Name, favpkg, used_shiny, num_years, os_type) 
# VALUES ('E', 'F', 'Q', 'Y', 'A'), ('C', 'W', 'V', 'V', 'V'), ('I', 'R', 'M', 'C', 'U'), 
# ('U', 'O', 'T', 'M', 'I'), ('B', 'L', 'I', 'O', 'D')" 

Außerdem Betrachten Sie RODBCs sqlSave, um den gesamten Datenrahmen an die Datenbank anzufügen: