┌ ┐ The Joy of SQL - If Properly Implemented Hannes Mühleisen Data Day Texas └ 1 ┘ % ┌ ┐ The Structured Query Language (SQL) Developed for IBM System R Pronounced "Sequel" Big Idea: Disconnect intent and execution Wildly Successful Still a Trillion Dollar Market └ 2 ┘ % ┌ ┐ SQL is Controversial The Good Declarative Optimization The Bad Optimization Clunky Syntax Strange Semantics Unhelpful Error Messages Vendor-Specific Syntax "Slow" The Ugly Vendor-Specific Semantics Oracle's pricing model "[SQL] IS SO BORING, MY DAD DOES THE SAME THING EVERYDAY" └ 3 ┘ % ┌ ┐ Thomas Neumann & Viktor Leis A Critique of Modern SQL And A Proposal Towards A Simple and Expressive Query Language CIDR 2024 └ 4 ┘ % ┌ ┐ But is it SQL's Fault? Partially. Standard is under-specified. Minimal example: type of of 1/2? Vendors mostly to blame Frozen Code Bases Millions of tests Week-long CI Parser Infrastructure from 1960s Corporate Sales does not care about DevEx "Golf Course Sales" Long list of check marks > Happy Eyeballs └ 5 ┘ % ┌ ┐ Happy Eyeballs! └ 6 ┘ % ┌ ┐ If your data fits in memory there is no advantage to putting it in a database: It will only be slower and more frustrating. Hadley Wickham └ 7 ┘ % ┌ ┐ You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '...' at line 1 └ 8 ┘ % ┌ ┐ Joy of SQL? └ 9 ┘ % ┌ ┐ Postgres hannes=# SELECT a,b,c, FROM t; ERROR: syntax error at or near "FROM" WHY?! No Reason. DuckDB hannes D SELECT a,b,c, FROM t; ┌───────┬───────┬───────┐ │ a │ b │ c │ │ int32 │ int32 │ int32 │ ├───────┼───────┼───────┤ │ 42 │ 43 │ 44 │ └───────┴───────┴───────┘ └ 10 ┘ % ┌ ┐ 'SQL' SELECT a, b, sum(c) FROM t GROUP BY a, b ---- ---- Frustrating! But not necessary. DuckDB SELECT a, b, sum(c) FROM t GROUP BY ALL DuckDB 2022 (PR #2899) Databricks 2023 Snowflake 2023 BigQuery 2024 Oracle 2025 PostgreSQL 2026 ISO SQL:202y 2026 Also: ORDER BY ALL └ 11 ┘ % ┌ ┐ Query this CSV: a,b,c 42,43,44 'SQL' CREATE TEMPORARY TABLE t(a int, b int, c int); COPY t FROM '/.../test.csv' (FORMAT csv, HEADER true); SELECT * FROM t; Clunky and pointless. DuckDB FROM test.csv; Magic! └ 12 ┘ % ┌ ┐ Magic is just someone spending more time on something than anyone else might reasonably expect. Teller └ 13 ┘ % ┌ ┐ What is the schema of this table? 'SQL' SELECT column_name, data_type, is_nullable FROM information_schema.columns WHERE table_name='t' ORDER BY ordinal_position; DuckDB DESCRIBE t; ┌───────────┐ │ t │ │ │ │ a integer │ │ b integer │ │ c integer │ └───────────┘ └ 14 ┘ % ┌ ┐ What is actually in this table? 'SQL' SELECT * FROM t LIMIT 10; DuckDB SUMMARIZE t; ┌─────────────┬─────────────┬─────────┬───┬─────────┬──────────────────┐ │ column_name │ column_type │ min │ … │ q75 │ null_percentage │ │ varchar │ varchar │ varchar │ … │ varchar │ decimal(9,2) │ ├─────────────┼─────────────┼─────────┼───┼─────────┼──────────────────┤ │ a │ INTEGER │ 42 │ … │ 42 │ 0.00 │ │ b │ INTEGER │ 43 │ … │ 43 │ 0.00 │ │ c │ INTEGER │ 44 │ … │ 44 │ 0.00 │ ├─────────────┴─────────────┴─────────┴───┴─────────┴──────────────────┤ │ 3 rows 12 columns (5 shown) │ └──────────────────────────────────────────────────────────────────────┘ └ 15 ┘ % ┌ ┐ Apply a function to many columns? 'SQL' SELECT min(a), min(b), min(c) FROM t; Just repeat yourself? No! DuckDB SELECT min(COLUMNS(*)) FROM t; SELECT min(COLUMNS(* EXCLUDE c)) FROM t; SELECT min(COLUMNS('a|b')) FROM t; Bonus Round: SELECT +(*COLUMNS('a|b')) FROM t; └ 16 ┘ % ┌ ┐ Spreadsheets = Pivot 'SQL' Nope DuckDB UNPIVOT t ON COLUMNS(*); ┌─────────┬───────┐ │ name │ value │ │ varchar │ int32 │ ├─────────┼───────┤ │ a │ 42 │ │ b │ 43 │ │ c │ 44 │ └─────────┴───────┘ └ 17 ┘ % ┌ ┐ Function Chaining 'SQL' repeat(substring(replace(replace(upper('asdf'),'A','X'),'S','O'),1,2),2); | Intutive? No! | | DuckDB | ('asdf').upper().replace('A','X').replace('S','O').substring(1,2).repeat(2); | | ------------------------------------- └ 18 ┘ % ┌ ┐ Macros What if I want to use the same complex expression in many places? 'SQL' No such feature. Just repeat the expression. Screw you! DuckDB Hold my beer. CREATE my_macro(x) AS x.upper().replace('A','X').replace('S','O').substring(1,2).repeat(2); SELECT my_macro('asdf'); + Table Macros! └ 19 ┘ % ┌ ┐ But wait, there's more! LIST / MAP / STRUCT / UNION / VARIANT CREATE OR REPLACE TABLE CREATE TABLE ... AS SELECT INSERT OR IGNORE / REPLACE INTO INSERT INTO ... BY NAME UNION BY NAME MERGE SELECT a: 42 [expr(x) FOR x IN [...] IF ...] ASOF / LATERAL / POSITIONAL JOIN ... Google: Friendly SQL DuckDB └ 20 ┘ % ┌ ┐ @@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@=....@@@@@@@@@@@@@@@@@@@ @@@@@@@@@...........@@@@@@@@@@@@@@@@@ @@@@@@@@.............:@@@@@@@@@@@@@@@ @@@@@@@...............@@@......@@@@@@@ @@@@@@@................@@.......@@@@@@ @@@@@@@...............@@@......@@@@@@@ @@@@@@@@..............@@@@@@@@@@@@@@@@ @@@@@@@@@...........@@@@@@@@@@@@@@@@@ @@@@@@@@@@@.....@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@ └ ┘ % ┌ ┐ Database [CLI] Clients. A sad story. Codebases from ancient times. Still think we are on some IBM terminal from 1970. No colors No autocomplete UTF unknown Kept alive, yes. But loved, no. War story: Actian Vectorwise Widespread problem. Even `psql` is pretty bad. > Certainly not nice for productive data analysis. Give SQL [more] of a bad rep. This won't stand! Huge update for CLI in DuckDB 1.5, coming mid-February. Let's make CLI a viable environment for data engineers! └ 21 ┘ % ┌ ┐ Schema Exploration First questions on every dataset. Which schemas/tables exist? What columns do they have? How big are they? State of the 'art': \d \d lineitem ... :/ DuckDB 1.5: .tables └ 22 ┘ % ──────────────────────────────── tpch-sf1000 ──────────────────────────────── ┌─────────────────────────┐┌───────────────────────┐┌─────────────────────────┐ │ lineitem ││ part ││ orders │ │ ││ ││ │ │ l_orderkey integer ││ p_partkey integer ││ o_orderkey integer │ │ l_partkey integer ││ p_name varchar ││ o_custkey integer │ │ l_suppkey integer ││ p_mfgr varchar ││ o_orderstatus varchar │ │ l_linenumber integer ││ p_brand varchar ││ o_totalprice decimal │ │ l_quantity decimal ││ p_type varchar ││ o_orderdate date │ │ l_extendedprice decimal ││ p_size integer ││ o_orderpriority varchar │ │ l_discount decimal ││ p_container varchar ││ o_clerk varchar │ │ l_tax decimal ││ p_retailprice decimal ││ o_shippriority integer │ │ l_returnflag varchar ││ p_comment varchar ││ o_comment varchar │ │ l_linestatus varchar ││ ││ │ │ l_shipdate date ││ 200.00 million rows ││ 1.50 billion rows │ │ l_commitdate date │└───────────────────────┘└─────────────────────────┘ │ l_receiptdate date │ │ l_shipinstruct varchar │ │ l_shipmode varchar │ │ l_comment varchar │ │ │ │ 6.00 billion rows │ └─────────────────────────┘ ... % ┌ ┐ Result Set Rendering "DuckBox" tpch-sf1000 D FROM lineitem SELECT count(*); ┌────────────────┐ │ count_star() │ <- Column Names │ int64 │ <- Data Types ├────────────────┤ │ 5999989709 │ │ (6.00 billion) │ <- Human-Readable Alternative └────────────────┘ └ 24 ┘ % ┌ ┐ Result Set Rendering "DuckBox" tpch-sf1000 D FROM lineitem LIMIT 1000000; ┌────────────┬───────────┬───────────┬───┬────────────┬────────────────────────┐ │ l_orderkey │ l_partkey │ l_suppkey │ … │ l_shipmode │ l_comment │ │ int32 │ int32 │ int32 │ … │ varchar │ varchar │ ├────────────┼───────────┼───────────┼───┼────────────┼────────────────────────┤ │ 1 │ 155189345 │ 7689361 │ … │ TRUCK │ to beans x-ray carefu… │ │ 1 │ 67309080 │ 7309081 │ … │ MAIL │ according to the fin… │ │ 1 │ 63699776 │ 3699777 │ … │ REG AIR │ ourts cajole above th… │ │ · │ · │ · │ … │ · │ · │ │ · │ · │ · │ … │ · │ · │ │ · │ · │ · │ … │ · │ · │ │ 98 │ 40215967 │ 215968 │ … │ REG AIR │ gular accounts after … │ │ 98 │ 109742650 │ 7242681 │ … │ TRUCK │ ly express asymptotes… │ │ 98 │ 44705610 │ 4705611 │ … │ AIR │ e special, special de… │ ├────────────┴───────────┴───────────┴───┴────────────┴────────────────────────┤ │ 1000000 rows (1.00 million rows, 6 shown) 16 columns (5 shown) │ └──────────────────────────────────────────────────────────────────────────────┘ └ 25 ┘ % ┌ ┐ FROM _; Audience Quiz: What does this do? `_` holds the last query result! E.g., Renderer eats crucial column or rows... change parameters and just re-query _ └ 26 ┘ % ┌ ┐ Long-Running Queries DuckDB's CLI can show a progress bar. And display an ETA. Revolutionary! tpch-sf1000 D SUMMARIZE lineitem; 5% ▕█▉ ▏(~8.2 minutes remaining) └ 27 ┘ % ┌ ┐ Autocomplete! Lots of things have autocomplete. Browsers WhatsApp Python Shells Entire industries are built around glorified autocomplete... But autocomplete in database clients? psql? Crickets? No longer! DuckDB CLI has advanced language, schema, and filename autocomplete We actually rewrote the whole SQL parser for this YACC/Bison -> PEG Mühleisen & Raasveldt: Runtime-Extensible Parsers, CIDR 2025 New parser will be available as a preview in 1.5 But already powers autocomplete! └ 29 ┘ % ┌ ┐ [TAB] table ( abort alter analyze attach begin call checkpoint comment commit copy create deallocate delete desc describe detach drop end execute explain export force from import insert install load merge pivot pivot_longer pivot_wider pragma prepare reset rollback select set show start summarize truncate unpivot update use vacuum values with [top-level keywords] └ 30 ┘ % ┌ ┐ SELECT [TAB] c_acctbal c_address c_comment c_custkey c_mktsegment c_name c_nationkey c_phone l_comment l_commitdate l_discount l_extendedprice l_linenumber l_linestatus l_orderkey l_partkey l_quantity l_receiptdate l_returnflag l_shipdate l_shipinstruct l_shipmode l_suppkey l_tax n_comment n_name n_nationkey n_regionkey o_clerk o_comment o_custkey o_orderdate ... [column names] └ 31 ┘ % ┌ ┐ SELECT * FROM [TAB] customer lineitem nation orders part partsupp region supplier ... [tables] FROM 'lineitem-[TAB] lineitem-sf1.parquet' lineitem-sf10.parquet' lineitem-sf100.parquet' [filenames] └ 32 ┘ % ┌ ┐ tpch-sf1000 D FROM sql_auto_complete('SELECT * FROM '); ┌───────────────────┬──────────────────┬─────────────────┬──────────────────┐ │ suggestion │ suggestion_start │ suggestion_type │ suggestion_score │ │ varchar │ int32 │ varchar │ uint64 │ ├───────────────────┼──────────────────┼─────────────────┼──────────────────┤ │ customer │ 14 │ table │ 0 │ │ lineitem │ 14 │ table │ 0 │ │ nation │ 14 │ table │ 0 │ │ · │ · │ · │ · │ │ · │ · │ · │ · │ │ · │ · │ · │ · │ │ disable_logging │ 14 │ table_function │ 0 │ │ disable_profiling │ 14 │ table_function │ 0 │ │ discard │ 14 │ keyword │ 0 │ ├───────────────────┴──────────────────┴─────────────────┴──────────────────┤ │ 100 rows (6 shown) │ └───────────────────────────────────────────────────────────────────────────┘ └ 33 ┘ % ┌ ┐ @@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@=....@@@@@@@@@@@@@@@@@@@ @@@@@@@@@...........@@@@@@@@@@@@@@@@@ @@@@@@@@.............:@@@@@@@@@@@@@@@ @@@@@@@...............@@@......@@@@@@@ @@@@@@@................@@.......@@@@@@ @@@@@@@...............@@@......@@@@@@@ @@@@@@@@..............@@@@@@@@@@@@@@@@ @@@@@@@@@...........@@@@@@@@@@@@@@@@@ @@@@@@@@@@@.....@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@ └ ┘ % ┌ ┐ DuckDB Ecosystem Update ~ 5M Website Visitors per Month # 26 on DB-Engines Relational Ranking > 150 Community Extensions ~ 1M DuckDB Downloads │ ~ 4M Extension Installs │ Every. Single. Day. > 60 TB Web Traffic │ LTS Releases starting with 1.4 DuckLake 1.0 & DuckDB 1.5 coming in February! └ 35 ┘ % ┌ ┐ DuckDB Labs Products Feature Prioritization Influence DuckDB Roadmap Features go into DuckDB core or extensions Long-running collaborations Dedicated Engineer(s) Successful track record, e.g. Encryption, Delta Lake, ... Enterprise Support SLA for Questions, Bugs, etc. Longer support for older versions Direct access to core devs ... Talk to me! └ 36 ┘ % ┌ ┐ Data Fear → Data Confidence └ 37 ┘ % ┌ ┐ @@@@@@@ @@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@=....@@@@@@@@@@@@@@@@@@@ @@@@@@@@@...........@@@@@@@@@@@@@@@@@ @@@@@@@@.............:@@@@@@@@@@@@@@@ @@@@@@@...............@@@......@@@@@@@ @@@@@@@................@@.......@@@@@@ @@@@@@@...............@@@......@@@@@@@ @@@@@@@@..............@@@@@@@@@@@@@@@@ @@@@@@@@@...........@@@@@@@@@@@@@@@@@ @@@@@@@@@@@.....@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@ duckdb.org @@@@@@@@@ ducklake.select └ ┘