Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sequel query with join and condition on the other table

Tags:

ruby

sequel

I'm pretty new to Sequel and I'm scratching my head trying to figure out how to get Sequel's API to generate the following trivial SQL:

          select f.* from first f
          join second s on f.second_id = s.id
          where s.deactivated = false

The best I could come up with is:

      First.join(:second, deactivated: false, id: :second_id)
        .paged_each do |first|
          # magic happens here
        end

But that does select * not select first.* and as a result gets confused about what id to order by for paging and throws PG::AmbiguousColumn: ERROR: ORDER BY "id" is ambiguous

This is using Sequel 5.9.0 and Postres 10.

Solution

Thanks to @engineersmnky's suggestion about qualify and some further reading here's the approach I ended up using.

      First.join(:second, id: :second_id, deactivated: false)
        .qualify
        .stream.each do |first|
          # magic happens here
        end

The qualify method call resolves the ambiguity (and ensures only first table gets returned.

I also added sequel_pg gem so I can use stream.each rather than paged_each. This has a better performance but also removes the need for the order by id that was causing me grief initially.

like image 953
Krzysztof Kozmic Avatar asked Jun 05 '18 01:06

Krzysztof Kozmic


People also ask

How do you join two tables based on conditions?

You join two tables by creating a relationship in the WHERE clause between at least one column from one table and at least one column from another. The join creates a temporary composite table where each pair of rows (one from each table) that satisfies the join condition is linked to form a single row.

Which of the given join will combine rows from different tables if the join condition is true?

The INNER JOIN keyword selects all rows from both the tables as long as the condition is satisfied. This keyword will create the result-set by combining all rows from both the tables where the condition satisfies i.e value of the common field will be the same.

Can we use join and WHERE clause together?

To use the WHERE clause to perform the same join as you perform using the INNER JOIN syntax, enter both the join condition and the additional selection condition in the WHERE clause. The tables to be joined are listed in the FROM clause, separated by commas. This query returns the same output as the previous example.


1 Answers

Disclaimer: I have never actually used sequel

There appears to be a method Sequel::Dataset#qualify that will do exactly what you are asking and should result in:

select first.* from first 
  join second on first.second_id = second.id
  where second.deactivated = false

I think the implementation would look like:

First.join(:second, id: :second_id)
    .where(Sequel[:second][:deactivated] => false) 
    #OR .where("second.deactivated": false)
    #OR .where{[[second[:deactivated],false]]}
    .qualify
    .paged_each do |first|
      # magic happens here
    end

Now if First and Second are properly associated Sequel::Models it appears the join condition can be inferred through association_join See Here from the docs e.g.

First.association_join(:second)
    .where(Sequel[:second][:deactivated] => false)
    .qualify
    .paged_each do |first|
      # magic happens here
    end
like image 161
engineersmnky Avatar answered Nov 15 '22 12:11

engineersmnky