Edit this page

Attach DuckDB Databases


Method 1: YAML Definition (SQL Code Block & getDefaultClient())

--- 
sql:
  base: ../../assets/data/duckdb/data_sample.db
---
import * as vgplot from "npm:@uwdata/vgplot";
import {getDefaultClient} from "observablehq:stdlib/duckdb";

const db = await getDefaultClient();

Local

USE base;
-- SHOW TABLES;

SELECT * 
FROM dim_SRDESC;

Remote (GitHub)

ATTACH 'https://raw.githubusercontent.com/renan-peres/datasets/refs/heads/master/loaders/duckdb/duckdb_database_sample.db' AS github;
USE github;
-- SHOW TABLES;

SELECT * 
FROM dim_SRDESC
LIMIT 10;

Remote (S3)

ATTACH 's3://duckdb-blobs/databases/stations.duckdb' AS s3;
-- SHOW DATABASES;

USE s3;

-- SHOW TABLES;

SELECT * 
FROM stations
LIMIT 10;

Responsive Input

// Get tables
const tables = await db.sql`
  SELECT CONCAT(database, '.', schema,'.' , name) AS table_name
  FROM (SHOW ALL TABLES)
  -- WHERE schema = 'main';
`;

// Create the select input and store its value
const selectedTable = view(Inputs.select(tables, {
  format: d => d.table_name
}));
// For your query display block
const result = await db.query(`SELECT * FROM ${selectedTable.table_name} LIMIT 10;`);

display(Inputs.table(result, {
  rows: 30,
  format: {
    url: (x) => x ? htl.html`<a href="${/^https?:\/\//.test(x) ? x : 'https://' + x}" target="_blank">${x}</a>` : ''
  }
}));

Interactive Code

// Create the textarea that updates based on the selected query
const prebuiltCode = view(Inputs.textarea({
  value: `USE s3;

-- SHOW TABLES;

SELECT * 
FROM stations
LIMIT 10;`,
  width: "880px",
  rows: 7,
  resize: "both",
  className: "sql-editor",
  style: { fontSize: "16px" },
  onKeyDown: e => {
    if (e.ctrlKey && e.key === "Enter") e.target.dispatchEvent(new Event("input"));
  }
}));
// Execute and display pre-built query results
const prebuiltQueryResult = db.query(prebuiltCode);
// display(Inputs.table(prebuiltQueryResult));

display(Inputs.table(prebuiltQueryResult, {
        rows: 30,
        format: {
          	url: (x) => x ? htl.html`<a href="${/^https?:\/\//.test(x) ? x : 'https://' + x}" target="_blank">${x}</a>` : ''
        }
      }));

Method 2: FileAttachment (DuckDBClient.of())


Local

// Initialize DuckDB with predefined tables
const db2 = await DuckDBClient.of({base: FileAttachment('../../../assets/loaders/duckdb/data.db')});
// Get tables
const tables2 = await db2.query(`
  SELECT CONCAT(database, '.', schema,'.' , name) AS table_name
  FROM (SHOW ALL TABLES)
  -- WHERE schema = 'main';
`);

// Create the select input and store its value
const selectedTable2 = view(Inputs.select(tables2, {
  format: d => d.table_name
}));

const result = await db2.query(`SELECT * FROM ${selectedTable2.table_name} LIMIT 10;`);
// display(Inputs.table(result));

display(Inputs.table(result, {
        rows: 30,
        format: {
          	url: (x) => x ? htl.html`<a href="${/^https?:\/\//.test(x) ? x : 'https://' + x}" target="_blank">${x}</a>` : ''
        }
      }));

Remote (GitHub)

// Initialize DuckDB with predefined tables
const db3 = DuckDBClient.of();
// Create the textarea that updates based on the selected query
const prebuiltCode2 = view(Inputs.textarea({
  value: `ATTACH 'https://raw.githubusercontent.com/renan-peres/datasets/refs/heads/master/loaders/duckdb/duckdb_database_sample.db' AS github;

USE github;

-- SHOW TABLES;

SELECT * 
FROM dim_SRDESC
LIMIT 10;`,
  width: "880px",
  rows: 9,
  resize: "both",
  className: "sql-editor",
  style: { fontSize: "16px" },
  onKeyDown: e => {
    if (e.ctrlKey && e.key === "Enter") e.target.dispatchEvent(new Event("input"));
  }
}));
// Execute and display pre-built query results
const prebuiltQueryResult2 = db3.query(prebuiltCode2);
// display(Inputs.table(prebuiltQueryResult));

display(Inputs.table(prebuiltQueryResult2, {
        rows: 30,
        format: {
          	url: (x) => x ? htl.html`<a href="${/^https?:\/\//.test(x) ? x : 'https://' + x}" target="_blank">${x}</a>` : ''
        }
      }));