# `QuackDB.DML`
[🔗](https://github.com/elixir-vibe/quackdb/blob/main/lib/quack_db/dml.ex#L1)

Small DuckDB DML SQL builders.

These helpers return SQL iodata for setup and example insert statements while
still allowing DuckDB expressions where needed. For large batches, prefer
`QuackDB.insert_rows/4`, `QuackDB.insert_columns/4`, or
`QuackDB.Explorer.insert_dataframe/4`.

# `merge_insert`

```elixir
@type merge_insert() :: {:insert, [atom() | String.t()]}
```

# `row`

```elixir
@type row() :: keyword(value()) | %{required(atom() | String.t()) =&gt; value()}
```

# `table`

```elixir
@type table() ::
  atom() | String.t() | {atom() | String.t() | nil, atom() | String.t()}
```

# `value`

```elixir
@type value() :: QuackDB.SQL.parameter() | {:expr, iodata()}
```

# `where`

```elixir
@type where() :: keyword(value())
```

# `delete_from`

```elixir
@spec delete_from(
  table(),
  keyword()
) :: {iodata(), [QuackDB.SQL.parameter()]}
```

Builds a parameterized `DELETE FROM ... WHERE ...` statement.

    {sql, params} =
      QuackDB.DML.delete_from(:events,
        where: [event_type: "session_entry", session_file: session_file]
      )

    QuackDB.query!(conn, sql, params)

`nil` values generate `IS NULL` predicates. `{:expr, sql}` values are emitted
directly for cases where a DuckDB expression is required.

# `insert_into`

```elixir
@spec insert_into(String.t() | atom(), [row()] | row()) :: iodata()
```

Builds an `INSERT INTO ... VALUES ...` statement.

# `insert_into_select`

```elixir
@spec insert_into_select(
  table(),
  [atom() | String.t()],
  table(),
  [atom() | String.t()],
  keyword()
) ::
  iodata()
```

Builds an `INSERT INTO ... SELECT ... FROM ...` statement.

# `merge_into`

```elixir
@spec merge_into(
  table(),
  keyword()
) :: iodata()
```

Builds a `MERGE INTO ... USING ...` statement.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
