Getting started

contoso gives you the same retail dataset in two ways: as tables bundled with the package, and as larger cloud versions you query through ‘DuckDB’.

Bundled tables

Loading the package makes eight tables available: sales, orders, orderrows, customer, product, store, fx and calendar. They need no download or connection.

library(contoso)

dplyr::glimpse(sales)
#> Rows: 7,794
#> Columns: 20
#> $ order_key     <dbl> 233000, 233100, 233100, 233100, 233200, 233200, 233200, …
#> $ line_number   <dbl> 0, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 0, 1, 2, 3, 0, 0, 1, 0,…
#> $ order_date    <date> 2021-05-18, 2021-05-19, 2021-05-19, 2021-05-19, 2021-05…
#> $ delivery_date <date> 2021-05-18, 2021-05-19, 2021-05-19, 2021-05-19, 2021-05…
#> $ customer_key  <dbl> 1855811, 1345436, 1345436, 1345436, 926315, 926315, 9263…
#> $ store_key     <dbl> 585, 550, 550, 550, 370, 370, 370, 370, 60, 60, 60, 9999…
#> $ product_key   <dbl> 1483, 499, 1512, 1490, 2512, 424, 1548, 312, 665, 623, 1…
#> $ quantity      <dbl> 2, 1, 3, 3, 3, 2, 3, 2, 3, 5, 7, 1, 3, 1, 2, 3, 3, 2, 2,…
#> $ unit_price    <dbl> 376.600, 148.500, 334.600, 180.600, 181.986, 404.925, 37…
#> $ net_price     <dbl> 376.60000, 130.68000, 287.75600, 176.98800, 172.88670, 3…
#> $ unit_cost     <dbl> 173.1800, 75.7050, 153.8740, 92.0780, 60.2980, 206.4450,…
#> $ currency_code <chr> "USD", "USD", "USD", "USD", "GBP", "GBP", "GBP", "GBP", …
#> $ exchange_rate <dbl> 1.00000, 1.00000, 1.00000, 1.00000, 0.70802, 0.70802, 0.…
#> $ gross_revenue <dbl> 753.200, 148.500, 1003.800, 541.800, 545.958, 809.850, 1…
#> $ net_revenue   <dbl> 753.20000, 130.68000, 863.26800, 530.96400, 518.66010, 7…
#> $ unit_discount <dbl> 0.00000, 17.82000, 46.84400, 3.61200, 9.09930, 16.19700,…
#> $ discounts     <dbl> 0.00000, 17.82000, 140.53200, 10.83600, 27.29790, 32.394…
#> $ cogs          <dbl> 346.3600, 75.7050, 461.6220, 276.2340, 180.8940, 412.890…
#> $ gross_margin  <dbl> 406.84000, 54.97500, 401.64600, 254.73000, 337.76610, 36…
#> $ unit_margin   <dbl> 203.42000, 54.97500, 133.88200, 84.91000, 112.58870, 182…

Join them on their _key columns:

sales |>
  dplyr::left_join(store, by = "store_key") |>
  dplyr::summarise(net_revenue = sum(net_revenue), .by = country_name) |>
  dplyr::arrange(dplyr::desc(net_revenue))
#> # A tibble: 9 × 2
#>   country_name   net_revenue
#>   <chr>                <dbl>
#> 1 Online            3919178.
#> 2 United States     1808404.
#> 3 Germany            431675.
#> 4 Canada             333493.
#> 5 United Kingdom     302591.
#> 6 Australia          221227.
#> 7 Netherlands        129077.
#> 8 France              88228.
#> 9 Italy               72067.

Larger datasets in ‘DuckDB’

create_contoso_duckdb() streams the Parquet files from cloud storage into an in-memory ‘DuckDB’ database. Pick a size by the number of sales rows:

size sales rows
"small" 7,794
"medium" 2,349,091
"large" 23,719,935
"mega" 237,245,485

"small" is the same data as the bundled tables. The other sizes cover a different date range and a much larger customer catalogue.

db <- create_contoso_duckdb(size = "medium")

The result is a list with one lazy table per dataset and the connection, db$con. Write dplyr as usual; it runs in ‘DuckDB’ until you collect():

db$sales |>
  dplyr::summarise(net_revenue = sum(net_revenue), .by = currency_code) |>
  dplyr::collect()

Use launch_ui() to browse every table in the ‘DuckDB’ UI, and disconnect when you are done:

launch_ui(db$con)

DBI::dbDisconnect(db$con, shutdown = TRUE)

Data dictionary

Every table and column is described in a data-dict file, with keys, joins and the formulas behind each measure:

system.file("extdata", "small", "data-dict.yaml", package = "contoso")

Use "cloud" in place of "small" for the dictionary of the larger sizes.

Next steps

The package also includes 1,127 fictional business reports about Contoso’s trading from May 2016 to the end of 2025. See The business reports to read them, and Searching the reports with ragnar to search them.