Statystyka a robienie makijażu

Wyszukuję ostatnio nietypowe przykłady zastosowań statystyki.
Trafiłem przy okazji tych poszukiwań, na ciekawe badania dotyczące zależności pomiędzy cechami twarzy a postrzeganym wiekiem.

Czy silniejszym makijażem brwi lub ust można dodać sobie lub odjąć kilka lat?

W pracy ,,Aspects of Facial Contrast Decrease with Age and Are Cues for Age Perception” z PLOS ONE, badacze porównują kontrasty lub kolory wokół brwi, oczu, ust z prawdziwym i postrzeganym wiekiem kobiety.

Oczywiście te cechy korelują z wiekiem, ciekawe jest jednak jak ładnie ilościowo można tą korelacją pokazać.

Więcej wyjaśnień i opis metodyki w cytowanym powyżej artykule, poniżej dwa wykresy.

Screen

t001

Czu to ciekawa ilustracja regresji liniowej?
A może znacie lepszą?

Esej 4: Percepcja danych

Pod adresem www.biecek.pl/Eseje/ indexDane.html udostępniliśmy esej o tytule ,,Percepcja danych”. Czwarty z serii ,,Wakacje z wizualizacją”.

We wtorek zorganizowaliśmy konkurs związany z tym esejem. W konkursie należało wskazać najczęstszą przyczynę zgonów, z trzech możliwych do wyboru, lub przyznać, że się nie zna najczęstszej przyczyny.

W zabawie wzięło udział 161 osób. Z tej grupy 52% (84 osoby) uznały, że najczęstszą przyczyną z wymienionych jest wypadek samochodowy, 40% (65 osób) uznało, że grypa lub zapalenie płuc, 6% (9 osób), że próby samobójcze, a niecałe 2% (3 osoby), przyznały, że nie wiedzą. Oczywiście próba jest reprezentatywna dla czytelników tego bloga (według google analytics są to głównie osoby z Warszawy) a nie dla jakiejś większej populacji.

plot_503071237

A co w rzeczywistości było najczęstszą przyczyną zgonów w 2010? Zgodnie z tym zbiorem danych w Polsce w 2010 roku grypa lub zapalenie płuc było przyczyną 3,42% zgonów, samobójstwo 2,21% zgonów, a wypadek drogowy 2.12% zgonów.

Zderzenie odpowiedzi w ankiecie i danych statystycznych jest bardzo ciekawe z kilku powodów.
Po pierwsze najczęstszą odpowiedzią był wypadek drogowy, który w rzeczywistości jest z tych trzech najrzadszą przyczyną.
Po drugie ponad połowa osób nie wiedziała ale jednak wybrała inną opcję niż 'nie wiem’ (a więc była przekonana, że +- wie, nie musiała strzelać)!

Jak to wyjaśnić?

Szczegółowo problem z percepcją ryzyk i prawdopodobieństw opisujemy właśnie w czwartym eseju. Opisujemy tam wiele innych ciekawych problemów, więc zapraszam do lektury. Moim zdaniem percepcja danych i zależności jest jednym z najciekawszych problemów z wizualizacją danych.

W konkursie wygrał numerek 92, czyli osoba o mailu pawel.*********@***b.pl. Gratulujemy! Skontaktujemy się mailowo. Niedługo kolejne konkursy.

Ciekawostka: Dlaczego ten esej otwiera zdjęcie ze Świątyni Uspokojonego Smoka, sławnej z ogrodu Zen? Mam kilka równoległych wyjaśnień. Sława tej świątyni, podobnie jak sława obrazu Mona Lisa (o kilka lat młodszego, również opisywanego w czwartym eseju) wydaje się być zupełnie przypadkowa a jednocześnie w retrospekcji łatwa do wytłumaczenia. Ogród, podobnie jak wiele zbiorów danych, jest znany z bogactwa możliwości interpretacji. Również, często ten ogród jest opisywany jako idealna abstrakcja, podobnie jak dane są abstrakcją. Coś pokazują, ale jednocześnie rzadko oferują idealną ostrość obrazu.

Ten esej to część zbioru ,,Odkrywać! Ujawniać! Objaśniać!” wydanego przez Fundację, dostępnego już w sprzedaży. O tym jak go kupić można przeczytać na stronie http://biecek.pl/Eseje/ indexZakup.html. Co trzy tygodnie na stronie http://biecek.pl/Eseje/ będziemy publikować kolejny rozdział w postaci elektronicznej, bezpłatnie, na otwartej licencji CC BY&SA.

Co zabija Polaków? Odpowiedz i wygraj książkę o wizualizacji danych!

Za dwa dni odkrywamy Esej o percepcji danych. Z tej okazji mamy mały konkurs. Tym razem stawka jest wyższa, można wygrać papierową wersję Esejów o wizualizacji danych.

Aby wziąć udział w konkursie, należy odpowiedzieć na poniższe pytanie.
Reguły:
1. W losowaniu biorą udział wszystkie odpowiedzi, nie tylko poprawne! Proszę więc nie szperać po rocznikach statystycznych ale odpowiedzieć zgodnie z przekonaniami / wyobrażeniami.
2. Jedna osoba może wziąć udział tylko raz w tej zabawie.
3. Liczą się tylko głosy oddane dziś i jutro (19-20 sierpnia).
4. Spośród odpowiedzi wylosuję jedną osobę, która otrzyma papierowe wydanie Esejów.

Skąd to pytanie i jaka jest odpowiedz?
Odpowiedź znajdziecie w czwartym eseju i czwartkowym wpisie. Interesują mnie częstości intuicyjnych odpowiedzi na poszczególne pytania. Dlatego odpowiadajcie zgodnie z intuicją. W losowaniu biorą udział wszystkie odpowiedzi, nie tylko poprawne.

Powodzenia w losowaniu. Książka czeka.

[Jeżeli powyższy formularz się nie wyświetla, proszę wysłać odpowiedź przez tę stronę]

Ściągawki z shiny i R Markdown

Przygotowanie pięciominutowego wystąpienia zajmuje często więcej czasu niż dwugodzinnego wykładu. Będąc ograniczonym pod względem ilości materiału, który możemy przedstawić, musimy wybrać najistotniejsze elementy, dopracować kolejność ich prezentacji oraz argumentacje.
Z tego też powodu, moje ulubione zadania zaliczeniowe dla studentów to: przygotuj sprawozdanie na maksymalnie 5 stron; przygotuj wizualizację mieszczącą się na stronie formatu A3; opracuj jednostronicowe podsumowanie określonej biblioteki R. Bardzo łatwo w takich projektach odczytać czy autor zna i potrafi pokazać odpowiedź na sedno problemu.

Z podobnego powodu lubię kolekcjonować tzw. cheatsheety, czyli ściągawki z wyciągiem najistotniejszych komend/funkcji określonego programu/pakietu. Dwie, które ostatnio przyciągnęły moją uwagę, to opracowane przez Garretta Grolemunda streszczenia R Markdown i Shiny.
Miniaturki poniżej.

PAZUR 2014 już za dwa miesiące

Słów kilka od organizatorów PAZURa.

Już za dwa miesiące odbędzie się Polski Akademicki Zlot Użytkowników R w Poznaniu! W związku z tym mamy dla Państwa kilka ważnych informacji.

Do tej pory mamy 50 zgłoszeń na udział w konferencji. Dla zainteresowanych mamy dobre wiadomości! Są jeszcze miejsca na warsztaty szkoleniowe, jak również na referaty dłuższe (20 minutowe) i krótsze (5 minutowe). W związku z tym serdecznie zapraszamy Państwa do aktywnego uczestnictwa w konferencji i zgłaszania się na warsztaty oraz przesyłania propozycji referatów poprzez formularz na stronie lub mailowo na adres pazur [at] konf.ue.poznan.pl.

Jednocześnie chcielibyśmy przypomnieć o możliwości udziału w konkursie wizualizacji danych dotyczących skoków narciarskich. Konkurs przeznaczony jest dla studentów (I i II stopień) oraz tegorocznych absolwentów. Do wygrania nagrody książkowe ufundowane przez fundację SmarterPoland.pl. Gorąco zachęcamy do udziału, jak również do przekazania tej informacji zainteresowanym osobom.

Chcieliśmy przypomnieć o ważnych terminach, które znajdują się poniżej.

01.09.2014 – zakończenie rejestracji na warsztaty
15.09.2014 – zakończenie rejestracji na konferencję oraz dokonywania wpłat za warsztaty
22.09.2014 – ogłoszenie listy uczestników warsztatów oraz harmonogramu konferencji
06.10.2014 – zakończenie wysyłania prac konkursowych
15.10.2014 – warsztaty towarzyszące konferencji
16 – 17.10.2014 – konferencja

Zachęcamy do śledzenia strony konferencji http://estymator.ue.poznan.pl/pazur/index.html.

W razie jakichkolwiek pytań prosimy o kontakt mailowy (pazur [at] konf.ue.poznan.pl)

Do zobaczenia w październiku !

Warsztaty Computerworld poświęcone wizualizacji danych

Jakiś czas temu pisałem o konferencji Big Data, organizowanej przez Computerworld, podczas której miałem przyjemność przedstawienia wyników z prostej eksploracji danych dotyczących wydarzeń na Ukrainie (chodzi o ten wpis).

Możliwości grafiki statystycznej okazały się interesujące dla wielu osób, w konsekwencji wspólnie z Computerworld przygotowujemy dwudniowe warsztaty poświęcone wizualizacji danych. Prelegentami będą Marcin Marciniak (prowadzący między innymi TechnoBloga) i ja (prowadzący tego bloga).

Warsztaty są przygotowane z myślą o analitykach, programistach i statystykach (warto znać jakiś język programowania, najlepiej R, i mieć przynajmniej podstawowe doświadczenie w analizie danych).

Więcej informacji o warsztatach znaleźć można tutaj.

Poszukiwana pomoc przy MOOC w ramach WSAD

WSAD to skrót od Warszawskiej Szkoły Analizy Danych, bardzo interesującego projektu, między innymi szkoły letniej, którego celem jest zwiększenie umiejętności analizy danych. Szkoła letnia już za nami, adresowana była ona głównie do doktorantów.

Teraz, w ramach WSAD przygotowywany jest MOOC, skrót od Massive open online course, czyli platforma (a dokładniej rozszerzenie platformy COME) i dwa kursy elektroniczne dotyczące analizy danych.
Oba, planowane w ramach MOOC kursy, będą adresowane do szerszej publiki. W tym osób, które mają w pracy jakiś kontakt z danymi, nie mają gruntownego statystycznego wykształcenia i chciałyby uzupełnić braki w edukacji.

Udział w kursach będzie bezpłatny.

Pomagam w organizacji obu internetowych kursów. Jeden z nich ma dotyczyć 'Statistical literacy’ z przykładami w użyciu takich zbiorów danych jak Eurostat czy European Social Survey (lub innych, zobaczymy). Drugi dotyczyć będzie wizualizacji danych. Prace nad tymi kursami nabiorą rozpędu prawdopodobnie koniec sierpnia/początek września.

Poszukuję osób, które chciałyby pomóc przy dopracowaniu szkieletu i opracowaniu materiałów jednego z tych kursów.
Poszukiwana jest jedna osoba/ dwie osoby o znacznym doświadczeniu w nauczaniu analizy danych, najlepiej ze znajomością R i jakąś wiedzą o kursach typu MOOC.
Finansowanie i zaplecze techniczne pozwoli na opracowanie naprawdę fajnych kursów.

Osoby zainteresowane pracą przy opracowaniu materiałów, proszone są o przesłanie mi [przemyslaw.biecek na gmail.com] maila do dnia 16 sierpnia, z kilkoma zdaniami o sobie, opisem doświadczenia w nauczaniu i najlepiej linkami/próbkami opracowanych materiałów. Proszę w temacie maila napisać [MOOC].

kRakowskie spotkania użytkowników R

Mamy cykliczne spotkania użytkowników R w Warszawie (SER), Poznaniu (PAZUR, spotkania co miesiąc a w październiku odbędzie się większa konferencja), były spotkania we Wrocławiu (WZUR). Czas na Kraków!

Inicjatorem jest Bartosz Sękiewicz. Planowana data rozpoczęcia to październik/listopad. Planowane miejsce spotkań to Wydział Matematyki i Informatyki UJ.

Osoby zainteresowane spotkaniami lub chcące dowiedzieć się czegoś więcej, znajdą niezbędne informacje na stronie eRka (www.erkakrakow.pl) oraz na facebookowym profilu (https://www.facebook.com/eRkaKrakow).

Serdecznie dopinguję tej inicjatywie. W Krakowie dużo się dzieje w przetwarzaniu i analizie danych, aż dziw że jeszcze nie ma spotkań użytkowników R. Niespokojne duchy z Krakowa, zainteresowane R powinny się spotkać i to zmienić.

Parameterized SQL queries

Mateusz Żółtak asked me to spread the word about his new R package for parameterized SQL queries. Below you can find the copy of package vignette. If you work with SQL in R you may find it useful.

The package RODBCext is an extension of the RODBC database connectivity package. It provides support for parameterized queries. This document describes what parameterized queries are and when they should be used. In addition some examples of ROBDCext usage are shown.

It is assumed that you already know the RODBC package and the basics of SQL and ODBC. If not, please read about them first, e.g. see the ODBC Connectivity vignette of the RODBC package.

1 What are parameterized queries for?

Parameterized queries (also known as prepared statements) are a technique of query execution which separates a query string from query parameters values. There are two main reasons for using this technique:

  • avoiding SQL injections,
  • speeding up query execution in some scenarios.

Both are discussed below.

2 SQL injections

SQL injection is an attack against your code which uses SQL queries. Malicious query parameter values are passed in order to modify and execute a query. If you use SQL data sources, it is highly likely that sooner or later your R code will experience a problem similar to an SQL injection (or an SQL injection itself). Consider the following:

  • Even data from trusted data sources (even SQL ones) can cause problems in SQL queries if use improper programming techniques.
  • Are you sure that your data came from a really trusted source?
  • All Shiny applications which process data from SQL data sources can be a target of an SQL injection attack.

2.1 Example – an apostrophe sign in data

Let us begin with a simple example illustrating how your own data can lead to problems similar to a SQL injections attack.

Imagine a simple SQL database with a table called cakes:

cake price
Chocolate cake 10
Strawberry cupcake 3
Kevin’s Cherry Tart 12.3

We receive a CSV data file containing the same database but with new prices. You are asked to update the database. So you write your R code as below:

library(RODBC)

connHandle <- odbcConnect("cakesDatabase")
newData <- read.csv("newData.csv", stringsAsFactors = F)

for(row in 1:nrow(newData)){
  query <- paste0(
    "UPDATE cakes 
     SET price = ", newData$price[row], " 
     WHERE cake = '", newData$cake[row], "'"
  )
  sqlQuery(connHandle, query)
}

odbcClose(connHandle)

Such a code will fail on a Kevin’s Cherry Tart because this name contains an apostrophe. The resulting query would be UPDATE cakes SET price = 12.3 WHERE cake = 'Kevin's Cherry Tart'; which is not a proper SQL query. To deal with the Kevin’s Cherry Tart we need to escape the apostrophe in the cake’s name so that the database knows that it doesn’t denote the end of the string value.

2.2 Example – simple SQL injection

There is a nice XKCD about that – see here. Let’s translate it into an example in R.

We have got a database of students with a table students

last_name first_name
Smith John
Lee Andrew
Wilson Linda

A new school year has begun and new students have come. We have just received a CSV file with the same structure as the table students and we are asked to add it to the database. So we prepare a simple script:

library(RODBC)

connHandle <- odbcConnect('studentsDatabase')
newStudents <- read.csv('newStudents.csv', stringsAsFactors = F)

for(row in 1:nrow(newStudents)){
  query <- paste0(
    "INSERT INTO students (first_name, last_name)
     VALUES (
       '", newStudents$first_name[row],"', 
       '", newStudents$last_name[row],"', 
     )"
  )
  sqlQuery(P, query)
}

odbcClose(connHandle)

Unfortunately one of our new students’ name is:

last_name first_name
Smith Robert’); DROP TABLE students; –

For this student our query would be:

INSERT INTO students (last_name, first_name)
  VALUES ('Smith', 'Robert'); DROP TABLE students; --')

These are in fact two SQL queries and one SQL comment:

  • INSERT INTO students (last_name, first_name) VALUES ('Smith', 'Robert');
  • DROP TABLE students;
  • --')

Execution of such a query can lead to a serious data loss (hopefully we have made a backup copy or do not have sufficient rights to drop the students table). To avoid such problems we should properly escape parameters values in our SQL queries.

2.3 How to escape values in SQL queries?

At this point we already know that we should properly escape parameters values in our SQL queries. There are many techniques of doing that:

  • Manually checking the data types.
  • Using parameterized queries.
  • Using high-level functions which escape values for us.

2.3.1 Manually checking data types

You can escape your data manually, e.g.

  • cast numeric columns to numbers using as.numeric(column) or sprintf(“%d %f”, integerColumn, realColumn),
  • cast dates using as.character(as.Date(column)),
  • escape strings using gsub(“‘“,”’’”, column),
  • etc.

This is possible but is also very error prone, especially when escaping string values. Everyone knows that apostrophes have to be escaped, but:

  • Different database systems may use different escape sequences (e.g. C-style with a backslash or repeat-style a with double apostrophe).
  • our database system may handle HTML/XML entities or inserting characters by a Unicode value (or many, many other strange ways of data input), so e.g. my’value or my\U0027value will be converted into my’value and then lead to errors in your query.

It is almost impossible to remember all caveats by yourself, so it is strongly advised not to use this method.

2.3.2 Using parameterized queries

Another solution is to separate the query string from its parameters (data). In such case a query execution is divided into two steps:

  • query parsing and planing,
  • passing parameter values to query and query execution.

As query parameters are passed separately, parameter values cannot modify (and break) the query string. To indicate places in the query where parameters will be placed, a special character is used, typically a question mark.

Let us rewrite our cakes example using the sqlExecute(connHandle, queryString, data) function from the RODBCext package:

library(RODBCext)

connHandle <- odbcConnect("cakesDatabase")
newData <- read.csv("newData.csv", stringsAsFactors = F)

query <- "UPDATE cakes SET price = ? WHERE cake = ?"
for(row in 1:nrow(newData)){
  sqlExecute(connHandle, query, newData[i, ])
}

odbcClose(connHandle)

We replaced the parameter values in query with a question mark and passed query and data as separate function parameters. We made our code not only SQL injection resistant, but also easier to read.

Moreover, the function function sqlExecute() supports vectorized data, so we can make it even simpler:

library(RODBCext)

connHandle <- odbcConnect("cakesDatabase")
newData <- read.csv("newData.csv", stringsAsFactors = F)

query <- "UPDATE cakes SET price = ? WHERE cake = ?"
sqlExecute(connHandle, query, newData)

odbcClose(connHandle)

2.3.3 Using high-level functions which deal with escaping values for us

This would be the most straightforward solution.

An excellent example is dplyr, which provides a complete R to SQL mapper and allows us to completely forget about the SQL. Another example are the sqlSave(), sqlUpdate(), sqlCopy() and sqlCopyTable() functions from the RODBC package which deal with escaping values for us.

The problem is that: * Dplyr escapes values rather naively. With respect to strings only simple ‘to’’ escaping is performed which is enough to prevent silly errors but will fail against more advanced SQL injections. * RODBC’s high-level functions escape values in a safe way (by internally using parameterized queries), but have very limited functionality. Interestingly, judging from the comments in the source code, the parameterized queries have been introduced to them not to make them safe but to improve speed.

2.4 Summary

When using SQL we must pay attention to escape query parameter values properly. The existing R database connectivity packages do not provide a completely reliable way of doing that. A set of SQL injections safe functions provides very limited functionality and more flexible functions are using naive escaping methods. That is why RODBCext is a preferred way to make your R code SQL injections safe.

I hope dplyr developers will switch to use parameterized queries internally at some point. This would provide R community with a brilliant and safe R to SQL mapper and to forget about a manual preparation of SQL queries.

3 Speeding up query execution using parameterized queries

SQL query execution is being performed in a few steps. The first two steps are

  • Parsing the query string into internal database query data structures.
  • Planning the query, e.g. deciding the order of joining the tables, indexes which should be used to execute a query, etc.

If we repeat the same query many times and only values of query parameters are changing, it will be faster to perform these steps only once and then reuse the already parsed and planed query. This can be achieved by using parameterized queries.

3.1 Example – big insert

A typical scenario is an insert of many rows to a table:

library(RODBCext)
connHandle <- odbcConnect('EWD') # my sample ODBC database
data <- data.frame(1:10000, letters[rep(1:10, 1000)])

# Ordinary query - paste0() called in every loop
system.time({
  for(row in 1:nrow(data)){
    query <- paste0("INSERT INTO my_table VALUES (", data[row, 1], "'", data[row, 2],"')")
    sqlQuery(connHandle, query)
  }
})
#   user  system elapsed 
#  5.384   2.288  16.397

# Ordinary query - paste0() called only once
system.time({
  queries <- paste0(
    "INSERT INTO my_table VALUES (", data[, 1], "'", data[, 2],"')"
  )
  for(query in queries){
    sqlQuery(connHandle, query)
  }
})
#   user  system elapsed 
#  2.088   2.028   7.255 

# Parameterized query
system.time({
  sqlExecute(connHandle, "INSERT INTO my_table VALUES (?, ?)", data)
})
#   user  system elapsed 
#  0.300   0.232   3.935 
odbcClose(connHandle)

3.2 Example – speeding up a SELECT query

Also repeated execution of a SELECT query can benefit from using parameterized variant:

library(RODBCext)
connHandle <- odbcConnect('EWD') # my sample ODBC database

pupils = sqlQuery(
  connHandle, "SELECT id_obserwacji FROM obserwacje LIMIT 10000", 
  stringsAsFactors = F
)[, 1]

# Ordinary query - paste0() called in every loop
system.time({
  for(i in pupils){
    query <- paste0(
      "SELECT count(*) 
       FROM testy_obserwacje JOIN testy USING (id_testu) JOIN arkusze USING (arkusz) 
       WHERE id_obserwacji = ", pupils[i]
    )
    tmp <- sqlQuery(connHandle, query)
    # some other computations here
  }
})
#   user  system elapsed 
# 10.896   1.508  61.424 

# Ordinary query - paste0() called only once
system.time({
  queries <- paste0(
    "SELECT count(*) 
     FROM testy_obserwacje JOIN testy USING (id_testu) JOIN arkusze USING (arkusz) 
     WHERE id_obserwacji = ", pupils
  )
  for(query in queries){
    tmp <- sqlQuery(connHandle, query)
    # some other computations here
  }
})
#   user  system elapsed 
# 11.016   1.108  51.766 

# Parameterized query
system.time({
  query = "
    SELECT count(*) 
    FROM testy_obserwacje JOIN testy USING (id_testu) JOIN arkusze USING (arkusz) 
    WHERE id_obserwacji = ?"
  sqlPrepare(connHandle, query)
  for(i in pupils){
    tmp = sqlExecute(connHandle, NULL, pupils[i], fetch=T)
    # some other computations here
  }
})
#   user  system elapsed 
# 12.140   0.312  26.468

The longer query string, the more complicated query planning and the more query repetitions, the bigger amount of time can be saved.

4 Parameterized SQL queries in R

Unfortunately all known to me R packages providing support for SQL databases lacks support for parameterized queries. Even the R DBI interface doesn’t define any methods which would allow to implement parameterized queries. The main reason for that is probably that R packages developers used to see SQL databases as just another storage backend for data frames rather than powerful data processing engines (which modern SQL databases already are).

4.1 RODBCext

RODBCext package tries to fill this gap by introducing parameterized queries support on the top of the RODBC package. RODBCext provides only two functions, both of them using database connection handlers from RODBC:

  • sqlPrepare(connHandle, SQLquery, errors = TRUE)
  • sqlExecute(connHandle, SQLquery, data, fetch = FALSE, errors = TRUE, ...)

4.1.1 sqlExecute()

Allows execution of SQL queries separated from query parameters values, e.g.:

library(RODBCext)
connHandle <- odbcConnect("myDatabase")

# good old RODBC call
data <- sqlQuery(connHandle, "SELECT * FROM myTable WHERE column = 'myValue'") 
# RODBCext equivalent
data <- sqlExecute(connHandle, "SELECT * FROM myTable WHERE column = ?", 'myValue', fetch = TRUE) 

odbcClose(connHandle)

The nice thing is that sqlExecute() (in opposite to sqlQuery()) supports vectorization. In the example below data will contain results of all five queries bound by rows.

library(RODBCext)
connHandle <- odbcConnect("myDatabase")

filterData <- data.frame('column1' = 1:5, column2 = c('a', 'b', 'c', 'd', 'e'))
data <- sqlExecute(connHandle, "SELECT * FROM myTable WHERE column1 = ? AND column2 = ?", filterData, fetch = TRUE)

odbcClose(connHandle)

Results can be also fetched separately using RODBC’s sqlGetResults(). This also provides a way to fetch results in parts:

library(RODBCext)
connHandle <- odbcConnect("myDatabase")

sqlExecute(connHandle, "SELECT * FROM myTable WHERE column = ?", 'myValue', fetch = FALSE)
data <- sqlGetResults(connHandle, max = 10) # fetch no more than 10 first rows
# data processing comes here
data <- sqlGetResults(connHandle) # fetch all other rows

odbcClose(connHandle)

As sqlExecute() uses internally sqlGetResults() to fetch results of the query, it also accept all parameters of the sqlGetResults():

library(RODBCext)
connHandle <- odbcConnect("myDatabase")

sqlExecute(
  connHandle, "SELECT * FROM myTable WHERE column = ?", 'myValue', 
  fetch = TRUE, stringsAsFactors = FALSE, dec = ",", max = 50, as.is = TRUE
)

odbcClose(connHandle)

4.1.2 sqlPrepare()

Parses a query string and plans a query. Query can be executed later using sqlExecute() with a parameter query set too NULL. This can provide some performance gain when executing the same query multiple times (see the chapter Speeding up query execution using parameterized queries). Usage example:

library(RODBCext)
connHandle <- odbcConnect('myDatabase') 

sqlPrepare(connHandle, "SELECT * FROM myTable WHERE column = ?") # prepare query

# for some reason (e.g. resources limits) data must be processed sequentialy
foreach(i in observations){
  data = sqlExecute(connHandle, NULL, i$column, fetch=T)
  # data processing for a given observations goes here
}
odbcClose(connHandle)