using DuckDB, DataFrames
con = DBInterface.connect(DuckDB.DB, ":memory:")
DBInterface.execute(con, """
CREATE TABLE tab (
name TEXT PRIMARY KEY,
data INTEGER
);
""")
DBInterface.execute(con, """
INSERT INTO tab VALUES
('a', 5),
('b', 10);
""")
DBInterface.execute(con, "SELECT * FROM tab;") |> DataFrame
# fails
stmt = DBInterface.prepare(con, """
UPDATE tab
SET data = :dat
WHERE name IN :names;
""")
DBInterface.execute(stmt, (:dat=50, :names=["b"]))
# works
stmt = DBInterface.prepare(con, """
UPDATE tab
SET data = ?
WHERE name IN ?;
""")
DBInterface.execute(stmt, [50, ["b"]])
DBInterface.execute(con, "SELECT * FROM tab;") |> DataFrame
In DuckDB, named parameters in prepared statements use $:
Of course in Julia, $ is an interpolation operator, so we need to escape it. So the latter part of your code might instead be
stmt = DBInterface.prepare(con, """
UPDATE tab
SET data = \$dat
WHERE name IN \$names;
""")
DBInterface.execute(stmt, (dat=50, names=["b"]))
DBInterface.execute(con, "SELECT * FROM tab;") |> DataFrame
giving
2Γ2 DataFrame
Row β name data
β String Int32
ββββββΌβββββββββββββββ
1 β a 5
2 β b 50
Thanks @jd-foster, I see. In that case, I am having trouble understanding the DBInterface docs (prepare a statement with named parameters GitHub - JuliaDatabases/DBInterface.jl: Database interface definitions for Julia). I thought I was using the correct interface. Or do you mean that there is no backend-agnostic way to use named parameters and it has to be changed for DuckDB, SQLite, etc?
Iβm not fully across this, but the interpolation does look to be dependent on the backend.
However GitHub - JuliaAPlavin/SQLCollections.jl might be useful here as the README tells us
There are no special parsing or interpolation rules to memorize, resulting in less implicit behavior.