首页 > 解决方案 > 尝试将 .xlsx 从 Shiny 加载到数据库的问题

问题描述

我很难编写一个闪亮的应用程序,让用户上传一个文件,然后使用一个按钮,它应该在通过 RSQLite 连接的数据库上创建一个新表,请参见下面的代码:

ui.R:

navbarPage(
"Ingreso de Data a Base de Datos",

fileInput('file1', 'Choose xlsx file',
accept = c(".xlsx")
),

actionButton("Load_DB_Button",
"Load Data",
style = "bordered",
width = "100%"),

mainPanel(

tableOutput('contents'))
) 

服务器.R:

Load_Data <- source("Load_Data.R")

library(readxl)

function(input, output, session){

output$contents <- renderTable({

req(input$file1)

inFile <- input$file1

read_excel(inFile$datapath, 1)

})

vals <- reactiveValues()

observeEvent(input$Load_DB_Button,{

vals$Load_Data_Out <- Load_Data()
showModal(modalDialog("Calculation Finished!"))

})

}

Load_Data.R:

library(RSQLite)
library(dplyr)

function(){

BD_CA_IDAAN <- DBI::dbConnect(RSQLite::SQLite(), "C:/Users/CBarrios/Desktop/Ex_Files_Data_Apps_R_Shiny/Exercise Files/07_03/Database/DB_CA_IDAAN.db")

df1 <- data.frame(contents)

dbWriteTable(BD_CA_IDAAN, "Test Table", df1)

message("Running Code")
return("Some Output")
}

我只需要它在数据库上创建一个表,其中包含通过 Excel 加载的数据。任何帮助将不胜感激。

标签: rsqliteshinyrsqlite

解决方案


我建议进行一些更改:

  • 你的函数没有命名,所以当它被定义时,它会立即被丢弃并且不可用。用一个名称存储它(我将使用Load_Data_func它来将它与Load_Data.R文件和您认为拥有的功能区分开来,随意重命名它),以便它可以保留和使用。

  • 您的函数假设它需要的数据已经在父环境中创建,从而超出了范围;明确地将其数据传递给它通常会更好(更安全,推荐等)。该函数还返回一些东西......一个静态字符串,然后您将其存储到一个反应值中,这似乎没有必要。我认为这个函数应该返回数据本身或表明它已正确存储在数据库中的东西。

    我会在这里向前迈出一大步:这dbWriteTable东西似乎有点脆弱。就像现在一样,默认参数是append=FALSE, overwrite=FALSE; 如果表存在,那么这将出错。你有两个选择,我将实现#1:

    1. 添加append=TRUE; 如果您不打算保留数据,则可以选择overwrite=TRUE 代替,每次都清除以前的数据。
    2. 创建一个随机表名并从函数中返回该表名。如果你走这条路,那么你将需要使用 areactiveVal将表名与返回的数据分开存储。(此处不演示此选项。)
  • 我稍微概括了这个函数,以便负责使用readxl. 该函数的假定意图是对数据进行某些操作,即将数据存储在数据库中。无论数据是显式传递的(也许您希望样本数据可用,在闪亮界面的其他地方选择)还是作为文件传递(这是默认值),函数都应该完成那部分。我在这里的更改是从主闪亮文件中删除文件读取,而不是仅传递路径/文件名。(请注意,现在确实应该使用命名的所有参数调用该函数,而不仅仅是位置参数。不是严格要求的,但为了清楚起见,它是有意义的。)

  • 将数据读入它自己的响应式,然后在output$contents块内使用该响应式(以及可选的任何您想要原始数据并且不打算使用“查询”的地方DBI)。

  • 按钮按下不合适observeEvent;我认为初始数据读取应该取决于按钮按下,而不是更改文件名,因为看起来你不想在按下按钮之前读取文件。为此,我稍微改变了反应流程。

  • 假设除了Load_Data.R文件之外,您可能还有其他文件对数据进行处理......我已将大多数库加载移至主文件。(例外是readxl,只有 需要Load_Data_func,所以它保留在 中Load_Data.R。如果您愿意,可以将其移动到server.R。)

  • 我将 sqlite 数据库文件位置的定义重新定位到顶层(在 内server.R),因为在我看来,该函数不应该对这样的东西进行硬编码。

  • 同样,假设您将使用 sqlite 数据库做更多的事情,而不仅仅是将数据转储到其中,您有两个选择:

    1. 将数据库连接对象(您的姓名BD_CA_IDAAN)存储在主server.R文件中,以便所有其他功能/反应(此处未包括)可以访问已打开的数据库;或者
    2. 打开它,存储数据,然后立即关闭它。我的函数版本将支持两者:要么传递数据库连接对象(并且数据将被附加,数据库连接不会关闭),要么传递文件名并且将在函数内打开数据库、附加数据和关闭数据库。
  • 可选:我不知道 sqlite 数据库是否仅用于数据的永久存储,或者您是否打算对其运行 SQL 查询。如果是后者,那么您可能不需要使用mydata(),尽管此处的大部分闪亮流程仍应保留。(如果您打算将所有 R 函数用于子集/重塑/重新计算/... on mydata(),则保持mydata()原样并将其作为框架使用。)

## ui.R
navbarPage(
  "Ingreso de Data a Base de Datos",
  fileInput('file1', 'Choose xlsx file',
            accept = c(".xlsx")
            ),
  actionButton("Load_DB_Button",
               "Load Data",
               style = "bordered",
               width = "100%"),
  mainPanel(
    tableOutput('contents')
  )
)
## server.R
library(RSQLite)
library(dplyr)

Load_Data <- source("Load_Data.R")

BD_CA_IDAAN <- "C:/Users/CBarrios/Desktop/Ex_Files_Data_Apps_R_Shiny/Exercise Files/07_03/Database/DB_CA_IDAAN.db"
### Optional:
# BD_CA_IDAAN <- DBI::dbConnect(RSQLite::SQLite(), BD_CA_IDAAN)

function(input, output, session) {

  mydata <- eventReactive(input$Load_DB_Button, {
    req(input$file1$datapath) # this is isolated
    dat <- Load_Data_func(path = input$file1$datapath, sheet = 1, db = BD_CA_IDAAN)
    showModal(modalDialog("Calculation Finished!"))
    dat
  })

  output$contents <- renderTable({
    req(mydata())
  })

}
## Load_Data.R
library(readxl)

Load_Data_func <- function(path, sheet = 1, db, data) {
  message("Running Code")
  if (missing(data)) {
    data <- readxl::read_excel(path, sheet = sheet)
  }
  if (is.character(db)) {
    # we were passed a file path
    db <- DBI::dbConnect(RSQLite::SQLite(), db)
    on.exit({ DBI::dbDisconnect(db); }, add = TRUE)
  }
  # this either returns 'TRUE' or it fails with an error, nothing else
  dbWriteTable(db, "Test Table", data, append = TRUE)
}

警告:我真的没有对此进行过广泛的测试。


推荐阅读