将 SQL 输入日期范围传递给 SHINY 中的查询

Posted

技术标签:

【中文标题】将 SQL 输入日期范围传递给 SHINY 中的查询【英文标题】:Passing a SQL input date range into a query in SHINY 【发布时间】:2016-08-04 14:49:37 【问题描述】:

我正在学习使用闪亮的仪表板并使用 sql 数据库 SQL-SERVER,我想直接从数据库中提取数据。本质上,这个想法是合并到表格中具有日期范围的起点和终点的列,将它们制成表格,然后绘制图表。

我发现了以下关于如何将 sql 输入语句传递给闪亮的帖子: How to pass input variable to SQL statement in R shiny?

不幸的是,当我尝试应用它时,我得到一个错误“下标超出范围;看起来查询没有被拉入。我已经单独对其进行了测试,并且能够提取数据并顺利完成每个步骤。我正在使用 RODBC 包,我想知道这是否是问题所在。以下是我的代码:

         library(stringr)
        library(RODBC)
          library(circlize)
         library(shinydashboard)
         library(shiny)

                ui <- dashboardPage(skin = "blue",
                dashboardHeader(title = "sample"),
                dashboardSidebar(disable = TRUE),
                dashboardBody(
                  # Boxes need to be put in a row (or column)
                  fluidRow(
                    box(title = "Route Volume", background = "green", solidHeader = TRUE,
                        plotOutput(outputId= 'plot2'))),
                    fluidRow( 
                      box(background= "green", dateRangeInput("dates", label = h3("Date Range"),start = '2016-06-01',
                                                              end = '2016-06-05')), width = 4

                      ))))

              server <- function(input, output) 
            database = odbcConnect("datatbase")
            output$plot2 = renderPlot(

            d = paste0("SELECT 
               top 30
           convert(char(10),datetime,121) as date, 
           cast(start_destination as varchar(3)) 
           + (',') + cast(final_destination as varchar(3)) as combo,
           count(cast(start_destination as varchar(3)) 
           + (',') + cast(final_destination as varchar(3))) as volume
           FROM
           trips
           WHERE datetime >= ",input$dates[1]," AND
           datetime < ",input$dates[2],"
           GROUP BY
           cast(start_destination as varchar(3)) 
           + (',') + cast(final_destination as varchar(3)),
           convert(char(10),datetime,121);")

        sql = sqlQuery(database, d)

           sql = data.frame(sql, do.call(rbind, str_split(sql$combo, ',')))
       colnames(sql)[colnames(sql)=="X1"] <- "From"
         colnames(sql)[colnames(sql)=="X2"] <- "To"
         sql = sql[,c(4,5,3)]
         sql = sql[order(sql$volume, decreasing = T),]
          chordDiagram(sql)
          circos.clear()

          )

          


          shinyApp(ui, server)

我确信这是一些愚蠢的错误,缺少引号或我对如何应用这些技术的误解。感谢帮助!

                ##adding edits by Dean to test



              database = odbcConnect("database")
             output$plot2 = renderPlot(
              if(input$dates[1]!= "") 
               d = paste0("SELECT 
            top 30
          convert(char(10),datetime,121) as date, 
          cast(start_destination as varchar(3)) 
          + (',') + cast(final_destination as varchar(3)) as combo,
          count(cast(start_destination as varchar(3)) 
          + (',') + cast(final_destination as varchar(3))) as volume
          FROM
           trips
           WHERE 
           datetime >= ",input$dates[1]," AND
           datetime < ",input$dates[2],"
           GROUP BY
          cast(start_destination as varchar(3)) 
          + (',') + cast(final_destination as varchar(3)),
           convert(char(10),datetime,121);")
         sql = sqlQuery(database, d) 

        #i assumed the if statement ended here so I put the 
        #bracket below 
           sql = data.frame(sql, do.call(rbind, str_split(sql$combo, ',')))
       colnames(sql)[colnames(sql)=="X1"] <- "From"
         colnames(sql)[colnames(sql)=="X2"] <- "To"
         sql = sql[,c(4,5,3)]
         sql = sql[order(sql$volume, decreasing = T),]
          chordDiagram(sql)
          circos.clear() 


    )

   

按照 NJburgo 的建议对服务器进行编辑 ################################NJburgo 建议############## ## #我收到错误:不知道如何将 input$dates 转换为上课日期

                       database = odbcConnect("database")
                           output$plot2 = renderPlot(
                           dates = as.Date(input$dates)
                           d = paste0("SELECT 
                       top 30
                      convert(char(10),datetime,121) as date, 
                     cast(start_destination as varchar(3)) 
                      + (',') + cast(final_destination as varchar(3)) as combo,
                       count(cast(start_destination as varchar(3)) 
                     + (',') + cast(final_destination as varchar(3))) as volume  
                     FROM
                    trips
                      WHERE 
                      datetime >= d '",input$dates[1],"' AND
                       datetime < d '",input$dates[2],"'
                        GROUP BY
                      cast(start_destination as varchar(3)) 
                       + (',') + cast(final_destination as varchar(3)),
                        convert(char(10),datetime,121);")
                   sql = sqlQuery(database, d) 


                   sql = data.frame(sql, do.call(rbind, str_split(sql$combo, ',')))
                 colnames(sql)[colnames(sql)=="X1"] <- "From"
                 colnames(sql)[colnames(sql)=="X2"] <- "To"
                 sql = sql[,c(4,5,3)]
                 sql = sql[order(sql$volume, decreasing = T),]
               chordDiagram(sql)
                   circos.clear() 

               )

             

【问题讨论】:

使用字符串连接构造 SQL 查询本身就是一个错误。日期和数字参数的意外转换只是它可能导致的问题之一。使用正确的parameterized queries 来避免所有引用、格式和安全问题 一种猜测是,在 input$dates 中包含值之前,闪亮正在运行 sql。我会在 sql 查询发生之前放置 print(input$dates[1])print(input$dates[2]),然后运行应用程序。这假设您从 Rstudio 运行,以便您可以在 Rstudio 窗口中看到它打印的内容。 嘿,院长。我尝试打印 input$dates 但没有任何区别。我确定问题就在这里,因为当日期被硬编码时,数据会毫无问题地提取。 我没想到印刷会有所作为。这只是一个调试步骤。它是打印日期还是打印空白? 明白了。它没有打印任何东西。只是空白,好像 Shiny 没有解释 input$dates 以放入 SQL 查询,这就是为什么查询也是空白的原因 【参考方案1】: ##########################找到答案。它需要将你们所有人的建议结合起来,以确保打印日期并进行转换。谢谢大家!下面是工作代码
                server <- function(input, output) 

             output$plot2 = renderPlot(
           database = odbcConnect("database")
              start_date = print(input$dates[1])
              end_date = print(input$dates[2])
              my_query="SELECT 
              top 30
                        convert(char(10),datetime,121) as date, 
                         cast(start_destination as varchar(3)) 
                        + (',') + cast(final_destination as varchar(3)) as combo,
                           count(cast(start_destination as varchar(3)) 
                           + (',') + cast(final_destination as varchar(3))) as volume  
                          FROM
                          trips
                              WHERE 
                           datetime >= DATE1 AND
                           datetime < DATE2
                            GROUP BY
                             cast(start_destination as varchar(3)) 
                           + (',') + cast(final_destination as varchar(3)),
                             convert(char(10),datetime,121);"

                my_query <- sub("DATE1",as.Date(start_date),my_query);
              my_query <- sub("DATE2",as.Date(end_date),my_query)
             sql = sqlQuery(database, paste(my_query))
            sql = data.frame(sql, do.call(rbind, str_split(sql$combo, ',')))
           colnames(sql)[colnames(sql)=="X1"] <- "From"
           colnames(sql)[colnames(sql)=="X2"] <- "To"
           sql = sql[,c(4,5,3)]
            sql = sql[order(sql$volume, decreasing = T),]
            chordDiagram(sql)
             circos.clear()
               )


             


             shinyApp(ui, server)

【讨论】:

【参考方案2】:

我不认为这是 R 的事情,更可能是 SQL,特别是如果您的查询使用 Shiny 之外的普通日期(提示:测试这个,报告回来!)。

对于 SQL 中的日期比较,总是必须这样转换日期:

...WHERE col_name >= d '2016-08-04'...

所以你必须在 R 中格式化日期。最简单的方法是使用格式:

format(Sys.Date(), "d '%Y-%m-%d'")

【讨论】:

如果您避免字符串连接并使用参数化查询,您不必必须转换日期。如果您 使用它们,则明确的日期格式是未分隔的格式,即20160804。在任何情况下,使用支持parameterized queries的 RODBCext 会更容易和更安全 感谢您的提示。 Panagiotos,我认为参数化查询肯定是我需要在此之后移动的地方,但我不确定这是这里的问题。查询在闪亮之外运行良好,它只是在闪亮内部停止。我继续尝试使用您的解决方案 NJBurgo 拉: WHERE col_name >= d '",input$dates[1],"' 以便将数据转换为日期格式但仍然没有成功(这在外面确实有效虽然有光泽)。我确实注意到,当我将日期硬编码到查询中时,效果很好。所以我认为问题在于输入$日期。不知道在哪里。有什么想法吗? @LoF10,来自 selectDate 的输入是一个字符串,需要转换。使用date &lt;- as.Date(input$date) 获取日期转换。然后你可以使用我发布的解决方案进行格式化,或者像@panagiotis-kanavos 建议的format(date, '%Y%m%d') 那样格式化。 嘿 NJburgo,感谢您的更新,所以我继续尝试。没用,但可能是我设置的方式。如果您可以快速查看,我将编辑添加到上面的帖子中。我不确定我是否应该同时转换日期 [1] 和日期 [2] 或只是“日期”。无论哪种方式,我都收到错误“不知道如何将 input$dates 转换为类 Date”。 我也尝试过 dates = format(input$dates, '%Y%m%d') 得到错误:$ 中的错误:$ 运算符对原子向量无效

以上是关于将 SQL 输入日期范围传递给 SHINY 中的查询的主要内容,如果未能解决你的问题,请参考以下文章

通过 Shiny Server 将 Shiny 输入传递给 R markdown

将反应输入传递到 R Shiny 中的绘图轴

将用户定义表中的日期值传递给 SQL Server 2008 存储过程

使用日期范围来改变服务器R Shiny中的直方图范围

R Shiny:将多个连续的反应传递给 selectInput

如何将 vb.net 中日期的空值传递给 sql 存储过程?