5

I used the following sql code in .Rmd document. However, I want to use the same SQL code in .Rnw document.

```{r label = setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, max.print = NA)
```

```{r, echo=FALSE, results='hide'}
library(DBI)
db <- dbConnect(RSQLite::SQLite(), dbname = "survey.db")
dbListTables(db)
```


```{sql, label = Q1, connection=db, tab.cap = "Table Caption"}
SELECT * 
  FROM Person;
```

Would prefer to get code formatting and output printing facility.

halfer
  • 19,824
  • 17
  • 99
  • 186
MYaseen208
  • 22,666
  • 37
  • 165
  • 309
  • Not sure if you saw this already (nor if it helps): http://yihui.name/knitr/demo/engines/ – Frank Aug 31 '16 at 18:36
  • 1
    Thanks @Frank for the link. I have seen that already but it is not useful. – MYaseen208 Aug 31 '16 at 18:47
  • 1
    Not sure if I understand the question - are you just looking for something like [this](https://gist.github.com/ClaudiusL/b27b682db8ed2261dc5c2b04b326f78a)? – CL. Sep 05 '16 at 19:11
  • @CL for your comment. I tried your code and getting this error: `Writing to file SQL2.tex Processing code chunks with options ... 1 : echo keep.source term verbatim (label = setup, SQL2.Rnw:6) Error in match.arg(options$results, c("verbatim", "tex", "hide")) : 'arg' should be one of “verbatim”, “tex”, “hide” Calls: -> SweaveParseOptions -> check -> match.arg Execution halted`. Any thoughts, please. – MYaseen208 Sep 06 '16 at 15:22
  • 1
    I think you're using Sweave instead of knitr. Please check your RStudio settings. Plus, it seems like there is no implicit `LIMIT` in RNW documents, so you'd better add something like `LIMIT 10` to your query. As soon as this works, we can turn to the question of how to format the output nicely ... – CL. Sep 06 '16 at 16:00
  • Thanks @CL for your help. It is working. Would highly appreciate if you change your comment to answer and also guide how to get good formating. Thanks – MYaseen208 Sep 06 '16 at 17:05
  • I'll do both as soon as I figured out *how* to do it. ;-) – CL. Sep 06 '16 at 17:07

1 Answers1

4

Porting the RMarkdown to RNW requires some tweaking:

  • Of course, chunk delimiters need to be adjusted: The RNW equivalent of ```{r, echo=FALSE} is <<echo=FALSE>>= and RNW chunks end with @. (See the minimal RNW example.)
  • Importantly, while chunks in RMarkdown documents always specify an engine, the engine in RNW is implicitly R unless the option engine is set. So ```{r} becomes simply <<>>=, but the equivalent of ```{sql} is <<engine="sql">>=.
  • RMarkdown includes some very useful magic when embedding SQL chunks, see knitr Language Engines: SQL on rmarkdown.rstudio.com. By default, results are rendered as a nice table and only the first 10 results are printed. In RNW, we need to take care of this on our own.

For embedding SQL in RMarkdown, note that the SQL connection must be passed to the SQL chunk via the connection option. The option output.var can be used to specify the name of the object to which the result of the query will be assigned.

A simple solution (see previous revision) would just assign the SQL result to an object, say res, using output.var and add another R chunk that prints res nicely, e.g. using xtable. However, there is a more elegant approach using hooks:

The example uses the SQLite sample database from sqlitetutorial.net. Unzip it to your working directory before running the code.

\documentclass{article}

\begin{document}
\thispagestyle{empty}
<<include=FALSE>>=
library(knitr)
library(DBI)

knit_hooks$set(formatSQL = function(before, options, envir) {
  if (!before && opts_current$get("engine") == "sql") {
    sqlData <- get(x = opts_current$get("output.var"))
    max.print <- min(nrow(sqlData), opts_current$get("max.print"))
    myxtable <- do.call(xtable::xtable, c(list(x = sqlData[1:max.print, ]), opts_current$get("xtable.args")))
    capture.output(myoutput <-do.call(xtable::print.xtable, c(list(x = myxtable, file = "test.txt"), opts_current$get("print.xtable.args"))))
    return(asis_output(paste(
      "\\end{kframe}", 
      myoutput,
      "\\begin{kframe}")))
  }
})

opts_chunk$set(formatSQL = TRUE)
opts_chunk$set(output.var = "formatSQL_result")
opts_chunk$set(max.print = getOption("max.print"))

@

<<echo=FALSE, results="hide">>=
db <- dbConnect(RSQLite::SQLite(), dbname = "chinook.db")
@

<<engine = "sql", connection=db, max.print = 8, xtable.args=list(caption = "My favorite artists?", label="tab:artist"), print.xtable.args=list(comment=FALSE, caption.placement="top")>>=
SELECT *  FROM artists;
@

\end{document}

A new chunk hook formatSQL is added. (Chunk hooks run whenever the corresponding chunk option is not NULL.) After a chunk with engine="sql", it reads the SQL results into sqlData. Then, it uses xtable to print the first max.print rows of the result.

By default, the chunk hook formatSQL is activated (i.e. it is globally set to TRUE) and SQL results are stored in formatSQL_result. The chunk option max.print controls the number of rows to be printed (set it to Inf to print all rows, always).

The table produced by xtable is highly customizable. The chunk option xtable.args is passed to xtable and print.xtable.args is passed to print.xtable. In the example these options are used to set a caption, a label and to suppress xtable's default comment.

Below the generated PDF. Note that syntax highlighting for non-R code in RNW requires installing highlight and adding the directory to path (Windows).

Output

Community
  • 1
  • 1
CL.
  • 14,577
  • 5
  • 46
  • 73
  • Great @CL. works like a charm. Would appreciate if you guide how to put the caption on the top of the table. Thanks a lot for your help. – MYaseen208 Sep 07 '16 at 16:50
  • 1
    @MYaseen208 Just pass `caption.placement="top"` to `print.xtable`. – CL. Sep 07 '16 at 16:51
  • Thanks @CL. for your help. There are two more thing to modify, `knitr2pdf` command from `knitr` show the `xtable` output on console which is not required. Also would like to know how to use `caption.placement="top"` and `connection=db` globally rather than locally. Any thoughts. – MYaseen208 Sep 07 '16 at 17:36
  • @MYaseen208 1) `xtable` output in console: See edit. 2) see `?print.xtable`: global option `xtable.caption.placement` 3) global `connection=db`: Don't think that this is possible. – CL. Sep 07 '16 at 18:06