cjbottaro

cjbottaro

I know this has been asked before, but I still can’t get it to work. I have code like this…

def case_stmt(input) do
  [c1, c2, c3, c4] = generate_clauses(input)

  Ecto.Query.dynamic([foo: a, bar: b], fragment("""
    CASE WHEN ? THEN 1 ELSE 0 END +
    CASE WHEN ? THEN 1 ELSE 0 END +
    CASE WHEN ? THEN 1 ELSE 0 END +
    CASE WHEN ? THEN 1 ELSE 0 END
  """, ^c1, ^c2, ^c3, ^c4))
end

Which works fine when the number of generated clauses is exactly 4. What about when it’s an unknown amount? I want to build up the SQL string using reduce.

There is a really good blog post about making SQL case statements with Ecto:

The problem is that it doesn’t work when you pass it a variable; it only works when you pass a literal.

Any ideas on how to make this work? My use case is user defined queries that are stored in a database. All the user input is validated before making the db records of course. “Just make a case clause for each field the user can search on.” doesn’t work because the schema itself is user defined.

Thanks for the help!

Showing Posts 1 to 7

fuelen

fuelen

The implementation of the macro uses fragments which must be defined at compile time, not at runtime. You cannot pass a list of when/then clauses.

Could you show what exactly do you want to run? How the data is stored and what SQL do you want to build? Maybe we can figure out a different algorithm

fuelen

fuelen

Tip: how would you implement dynamic cond in Elixir? You cannot pass conditions dynamically as well.

dimitarvp

dimitarvp

Why not separate them and do the summing in Elixir? You can also just use select_merge with dummy map keys and then use the resulting map’s values and sum that, similarly to this thread: Aggregate multiple dynamically selected columns in Ecto (without group by) - #3 by zackmichener

def case_stmt(input) do
   clauses = generate_clauses(input)
   bindings = [foo: a, bar: b]

   Enum.reduce(clauses, false, fn clause, query ->
     Ecto.Query.dynamic(
       bindings,
       fragment("CASE WHEN ? THEN 1 ELSE 0 END", ^clause) or ^query
     )
   end)
end
LostKobrakai

LostKobrakai

This might help with variable number of elements, where you don‘t know the number of elements at compile time. Not sure if it works with CASE though.

dimitarvp

dimitarvp

I realize that, yeah. Shame we don’t use a placeholder repo for such forum interactions. Somebody should get to that one day. :slight_smile:

cjbottaro

cjbottaro OP

Figured it out after chasing down those ideas, but ultimately went a different route (I think).

clauses = generate_clauses(input)

clause_count = Enum.reduce(clauses, nil, fn clause, acc ->
  q = Ecto.Query.dynamic(
    [foo: a, bar: b],
    fragment("CASE WHEN ? THEN 1 ELSE 0 END", ^clause)
  )
  
  if acc do
    Ecto.Query.dynamic([foo: a, bar: b], ^q + ^acc)
  else
    q
  end
end)

Ecto.Query.from(..., select_merge: ^%{clause_count: clause_count})

I need it done in SQL because I’m going to use that count in a where clause.

Very cool! I had been knee deep in Ecto docs for the past couple of days and still managed to miss that. Going to have to tuck that away in my head for later use. I tried using it here with a like a fragment("sum(?)", splice(clauses)) but it didn’t work cuz that’s not how sql sum works… :grimacing:

dimitarvp

dimitarvp

Oh that’s pretty clever. Nice job!

— All posts loaded —

Where Next? Top

Trending in Questions Top

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
jaybe78
Hello, I’m developing a online persistent chat system (what’s app) like using elixir/dynamodb/aws for a mobile app(flutter). The diffic...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New

Other Trending Topics Top

garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New
webofbits
Aludel - LLM Evaluation Workbench Aludel is an embeddable Phoenix LiveView dashboard for evaluating and comparing LLM prompts across mult...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews