I've run into this issue one too many times to not take a stab at writing my own work-around. Personally, I ran into this same issue with Microsoft SQL Server, but I figured this same solution would work for SQLite.  I'm working with:
- Database: Microsoft SQL Server hosted in Azure
- R: 3.5.0
- DBI: 1.0.0
- odbc: 1.1.6
- OS: Ubuntu 18.04
Approach:
I wanted to avoid looping through rows for the sake of efficiency. I found that mapply and paste0 could be combined in a more column-oriented fashion.
I'll admit it's a bit "hacky," but it's been working well for myself. Use at  your own risk; I'm only using this for a small side project, not an enterprise solution. Efficiency shouldn't be that big of an issue anyway, since there's a 1000 row limit on inserts anyway.
Replacement for "sqlAppendTable":
db_sql_append_table <- function(p_df, p_tbl) {
    # p_df: data.frame that contains the data to append/insert into the table
    # the names must be the same as those in the database
    # p_tbl: the name of the database table to insert/append into
    
    num_rows <- nrow(p_df)
    num_cols <- ncol(p_df)
    requires_quotes <- sapply(p_df, class) %in% c("character", "factor", "Date")
    commas <- rep(", ", num_rows)
    quotes <- rep("'", num_rows)
    
    str_columns <- ' ('
    column_names <- names(p_df)
    
    for(i in 1:num_cols) {
        if(i < num_cols) {
            str_columns <- paste0(str_columns, column_names[i], ", ")
        } else {
            str_columns <- paste0(str_columns, column_names[i], ") ")
        }
    }
    
    str_query <- paste0("INSERT INTO ", p_tbl, str_columns, "\nVALUES\n")   
    str_values <- rep("(", num_rows)
    
    for(i in 1:num_cols) {
        
        # not the last column; follow up with a comma
        if(i < num_cols) {
            if(requires_quotes[i]) {
                str_values <- mapply(paste0, str_values, quotes, p_df[[column_names[i]]], quotes, commas)        
            } else {
                str_values <- mapply(paste0, str_values, p_df[[column_names[i]]], commas)
            }
            
        # this is the last column; follow up with closing parenthesis
        } else {
            if(requires_quotes[i]) {
                str_values <- mapply(paste0, str_values, quotes, p_df[[column_names[i]]], quotes, ")")
            } else {
                str_values <- mapply(paste0, str_values, p_df[[column_names[i]]], ")")
            }
        }
    }
    
    # build out the query; collapse values with comma & newline; end with semicolon;
    str_values <- paste0(str_values, collapse=",\n")
    str_query <- paste0(str_query, str_values)
    str_query <- paste0(str_query, ";")
    return(str_query)
}
Calling the function:
I wanted to keep this as similar to the original sqlAppendTable function as possible. This function only constructs the query.
You still have to wrap this function in a call to dbExecute() to actually insert/append rows to the database.
dbExecute(conn=conn, statement = db_sql_append_table(my_dataframe, "table_name"))
EDIT
- Added "Date" as one of the types that needs to be quoted by this function as well. Thanks for that comment!