Active record where.not returns empty array - sql

Following command
Fight.last.fight_logs.where(item_id: nil)
generates sql:
Fight Load (0.3ms) SELECT "fights".* FROM "fights" ORDER BY "fights"."id" DESC LIMIT $1 [["LIMIT", 1]]
FightLog Load (0.2ms) SELECT "fight_logs".* FROM "fight_logs" WHERE "fight_logs"."fight_id" = $1 AND "fight_logs"."item_id" IS NULL LIMIT $2 [["fight_id", 27], ["LIMIT", 11]]
and returns:
#<ActiveRecord::AssociationRelation [#<FightLog id: 30, fight_id: 27, attack: 0, block: 0, item_id: nil, user_id: 1, damage: 11.0, created_at: "2017-11-02 16:20:55", updated_at: "2017-11-02 16:20:57">, #<FightLog id: 31, fight_id: 27, attack: 0, block: 0, item_id: nil, user_id: 20, damage: 3.0, created_at: "2017-11-02 16:20:57", updated_at: "2017-11-02 16:20:57">, #<FightLog id: 33, fight_id: 27, attack: 0, block: 0, item_id: nil, user_id: 1, damage: 1.0, created_at: "2017-11-02 16:21:40", updated_at: "2017-11-02 16:21:40">, #<FightLog id: 32, fight_id: 27, attack: 0, block: 0, item_id: nil, user_id: 20, damage: 7.0, created_at: "2017-11-02 16:21:33", updated_at: "2017-11-02 16:21:40">, #<FightLog id: 34, fight_id: 27, attack: 0, block: 0, item_id: nil, user_id: 1, damage: 12.0, created_at: "2017-11-02 16:21:47", updated_at: "2017-11-02 16:21:48">, #<FightLog id: 35, fight_id: 27, attack: 0, block: 0, item_id: nil, user_id: 20, damage: 14.0, created_at: "2017-11-02 16:21:48", updated_at: "2017-11-02 16:21:48">]>
but
Fight.last.fight_logs.where.not(item_id: 1)
generates sql:
Fight Load (1.0ms) SELECT "fights".* FROM "fights" ORDER BY "fights"."id" DESC LIMIT $1 [["LIMIT", 1]]
FightLog Load (0.8ms) SELECT "fight_logs".* FROM "fight_logs" WHERE "fight_logs"."fight_id" = $1 AND ("fight_logs"."item_id" != $2) LIMIT $3 [["fight_id", 27], ["item_id", 1], ["LIMIT", 11]]
and returns:
#<ActiveRecord::AssociationRelation []>
How it is possible? What i'm doing wrong?

You should specify NULL value in your query since you have it in your database:
Fight.last.fight_logs.where('item_id != ? OR item_id IS NULL', 1)
This is just how SQL works:
select 1 != NULL;
+-----------+
| 1 != NULL |
+-----------+
| NULL |
+-----------+
You can look at this answer to clarify the issue.
Also, I would recommend avoiding using default NULL values in your database, there is nice answer about it. You can simply use default: 0, null: false your case.

Related

Group By with multiple Objects vb.net

I have a list as following
list1 = [
{meal: {id: 1, version: 0}, type: {id: 2, version: 0}, adjCount: 1, systemCount: 0},
{meal: {id: 1, version: 0}, type: {id: 2, version: 0}, adjCount: 2, systemCount: 0},
{meal: {id: 2, version: 0}, type: {id: 1, version: 0}, adjCount: 4, systemCount: 0},
{meal: {id: 2, version: 0}, type: {id: 1, version: 0}, adjCount: 7, systemCount: 0},
]
I'm looking for a result such as it returns both mealId and type id with it's respective totals
As
{meal: {id: 1, version: 0}, type: {id: 2, version: 0}, adjCount: 3, systemCount: 0},
{meal: {id: 2, version: 0}, type: {id: 1, version: 0}, adjCount: 11, systemCount: 0}
I tried Using Linq with following code
List.GroupBy(Function(myItem) New MyObject With {.mealTypeId = myItem.Meal.Id, .countTypeId = MyItem.Count.Id}).
Select(Function(g) New With
{
.MealTypeId = g.Key.MealTypeId,
.CountTypeId = g.Key.CountTypeId,
.AdjustmentCount = g.Sum(Function(i) i.AdjustmentCount),
.SystemCount = g.Sum(Function(i) i.SystemCount)
}
but it doesn't return the expected output. Any Help will be greatly appreciated, I very rarely ask questions here so please forgive any mistakes I might have done in describing the issue.

Rails Active Record group query in SQLite vs Postgres

I am getting an error when running a query in SQLite vs Postgres with Active Record. There is an aggregate function error in Postgres but nothing in SQLite. My question is, what is SQLite doing here? Is it ignoring the group? Notice that GROUP BY "song" doesn't return an error.
SQLite output:
Playlist.where(user_id:user.id).group(:song)
Playlist Load (0.3ms) SELECT "playlists".* FROM "playlists" WHERE
"playlists"."user_id" = ? GROUP BY "song" [["user_id", 1]]
=> #<ActiveRecord::Relation [#<Playlist id: 2, user_id: 1, song_id: 1,
created_at: "2017-04-27 01:18:01", updated_at: "2017-04-27 01:18:01">]>
Playlist.where(user_id:user.id).group(:song_id)
Playlist Load (0.4ms) SELECT "playlists"."id", "playlists"."user_id",
"playlists"."song_id" FROM "playlists" WHERE "playlists"."user_id" = ?
GROUP BY "song" [["user_id", 1]]
=> #<ActiveRecord::Relation [#<Playlist id: 2, user_id: 1, song_id:
1, created_at: "2017-04-27 01:18:01">]>
Playlist.where(user_id:user.id).group(:id,:song_id)
Playlist Load (0.2ms) SELECT "playlists".* FROM "playlists" WHERE
"playlists"."user_id" = ? GROUP BY "playlists"."id",
"playlists"."song_id" [["user_id", 1]]
=> #<ActiveRecord::Relation [#<Playlist id: 1, user_id: 1, song_id: 1,
created_at: "2017-04-27 01:18:00", updated_at: "2017-04-27 01:18:00">,
#<Playlist id: 2, user_id: 1, song_id: 1, created_at: "2017-04-27
01:18:01", updated_at: "2017-04-27 01:18:01">]>
Playlist.where(user_id:user.id).group(:song).count
(0.2ms) SELECT COUNT(*) AS count_all, "playlists"."song_id" AS
playlists_song_id FROM "playlists" WHERE "playlists"."user_id" = ?
GROUP BY "playlists"."song_id" [["user_id", 1]]
Song Load (2.1ms) SELECT "songs".* FROM "songs"
WHERE "songs"."id" = ? LIMIT 1 [["id", 1]]
=> {#<Song id: 1, title: "A song", artist: "Artist", user_id: 1,
created_at: "2017-04-27 01:17:39">=>2}
Postgres:
Playlist.where(user_id:user.id).group(:song_id)
ActiveRecord::StatementInvalid: PG::GroupingError: ERROR: column
"playlists.id" must appear in the GROUP BY clause or be used in an
aggregate function
SELECT "playlists".* FROM "playlists" WHERE "playlists"."user_id" = $1
GROUP BY "playlists"."song_id"
Playlist.where(user_id:user.id).group(:id,:song_id)
Playlist Load (0.6ms) SELECT "playlists".* FROM "playlists" WHERE
"playlists"."user_id" = $1 GROUP BY "playlists"."id",
"playlists"."song_id" [["user_id", 1]]
=> #<ActiveRecord::Relation [#<Playlist id: 1, user_id: 1, song_id: 1,
created_at: "2017-04-27 01:25:34", updated_at: "2017-04-27 01:25:34">,
#<Playlist id: 2, user_id: 1, song_id: 1, created_at: "2017-04-27
01:25:36", updated_at: "2017-04-27 01:25:36">]>
Playlist.where(user_id:user.id).group(:song).count
(0.5ms) SELECT COUNT(*) AS count_all, "playlists"."song_id" AS
playlists_song_id FROM "playlists" WHERE "playlists"."user_id" = $1
GROUP BY "playlists"."song_id" [["user_id", 1]]
Song Load (0.3ms) SELECT "songs".* FROM "songs" WHERE "songs"."id" =
$1 LIMIT 1 [["id", 1]]
=> {#<Song id: 1, title: "A song", artist: "Artist", user_id: 1,
created_at: "2017-04-27 01:25:26", updated_at: "2017-04-27
01:25:26">=>2}
A common rule for group by: you may select only columns listed in group by and aggregate functions. This approach supported by sql standard and will work in any sql database.
If you are selecting columns not listed in a group by clause, for example select * … group by song_id, it may work in some databases and will not work in others.
If you specify selected columns in your code it will work:
Playlist.
where(user_id:user.id).
select("song_id").
group(:song_id)
You may read details about group by in PostgreSQL documentation: https://www.postgresql.org/docs/current/static/sql-select.html#SQL-GROUPBY

ActiveRecord ordering by relation

Loan.includes(:decisions).map{|l| l.decisions.last.try(:smart_rate)}
=> [2, nil, 2, 1, 4, 4, 1, nil, nil, nil, nil, 1, nil, 1, nil, 1, nil, nil, nil, 3, nil, 3, 1, 1, nil, 3, 1, 1, 4, 1, 1, 1, nil, 2, 1, nil, 1, nil, 1, 1, nil, 3, nil, 1, 1, 1, 1, 1, 1, 1]
I'd like to sort Loans by their last decision's smart_rate. I'm not trying to sort the array, but the resulting Loan::ActiveRecord_Relation.
Can this be done via ActiveRecord?
If you have a relationship on Decision then you could do this, the Loans should be in the correct order in the returned hash.
Decision.where(...).includes(:loan).order(:smart_rate).map(&:loan).uniq

ActiveRecord where.not is not working/ weird behavior

User has_many Plans. I'm trying to find the IDs of all Users that do NOT have a Plan with status of "canceled". Would love to know what's explaining the behavior below.
For context, what should be returned is this:
User.select { |u| u.plans.select { |p| p.status != "canceled" }.count > 0 }.map(&:id)
# => [27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 41, 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 61, 62, 63]
Here's what I'm getting:
# statement 1
User.joins(:plans).where.not("plans.status" => "canceled").map(&:id)
# User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "plans" ON "plans"."user_id" = "users"."id" WHERE ("plans"."status" != 'canceled')
# => [44]
# statement 2
User.joins(:plans).where("plans.status != ?", "canceled").map(&:id)
# User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "plans" ON "plans"."user_id" = "users"."id" WHERE (plans.status != 'canceled')
# => [44]
# statement 3
User.joins(:plans).where("plans.status == ?", nil).map(&:id)
# User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "plans" ON "plans"."user_id" = "users"."id" WHERE (plans.status == NULL)
# => []
# statement 4
User.joins(:plans).where("plans.status" => nil).map(&:id)
# User Load (0.7ms) SELECT "users".* FROM "users" INNER JOIN "plans" ON "plans"."user_id" = "users"."id" WHERE "plans"."status" IS NULL
# => [27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 41, 44, 42, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 60, 62, 63]
Questions:
Why are statement 3 and 4 not returning the same result?
Why are statement 1 and 2 (fortunately these are the same and are returning the same result) not returning the same result as statement 4? For context, I'd rather not search on nil, but on "canceled". And I can confirm that all plans have either a status of nil or "canceled"
UPDATE PER REQUEST
# plan with nil status
Plan.where(status: nil).first
# => <Plan id: 1, zipcode: "94282", selected_plan: 1, meal_type: "Chef's choice (mixed)", most_favorite: "", least_favorite: "", allergies: "", start_date: "2015-05-27 00:00:00", delivery_address: "d", delivery_instructions: "", phone1: "10", phone2: "222", phone3: "2222", agree_tos: true, user_id: 20, created_at: "2015-05-24 05:18:40", updated_at: "2015-06-21 04:54:31", stripe_subscription_id: nil, stripe_invoice_number: nil, cancel_reason: nil, cancel_reason_other: nil, nps: nil, nps_open: nil, cancel_open: nil, status: nil, referred_by_code: nil>
# plan with canceled status
Plan.where(status: "canceled").first
# => <Plan id: 20, zipcode: "12345", selected_plan: 5, meal_type: "Meat (with veggies)", most_favorite: "", least_favorite: "", allergies: "", start_date: "2015-06-08 00:00:00", delivery_address: "asdf", delivery_instructions: "", phone1: "333", phone2: "333", phone3: "3333", agree_tos: true, user_id: 38, created_at: "2015-06-01 21:39:54", updated_at: "2015-06-23 06:23:10", stripe_subscription_id: "sub_6OKkJoNx2u8ZXZ", stripe_invoice_number: 0, cancel_reason: nil, cancel_reason_other: "", nps: 6, nps_open: "", cancel_open: "", status: "canceled", referred_by_code: nil>
Answer to Question 1:
You missed the concept that in conditional sql, the arguments that follow the condition are replaced in place of ? not compared to. So, replace the double == with =.
User.joins(:plans).where("plans.status = ?", nil).map(&:id)

rails geocoder near_by result join query returns active record relation

the result produced by
locations_by_geocoder = Location.near([params[:latitude], params[:longitude]], params[:radius], :units => :km)
and
locations_by_where = Location.where(:id => [7, 10, 9, 8])
are the same
location_by_geocoder output is
[#<Location id: 7, country: nil, state: nil, city: nil, locality: nil, name: "Coffee On Canvas", latitude: "12.93516201597191", longitude: "77.63097871416265", created_at: "2014-03-29 15:20:34", updated_at: "2014-03-29 15:20:34", address: "#84, S.T.Bed Layout, 4th Block Koramangala", id_location: "cd49dfa966245b12">,
#<Location id: 10, country: nil, state: nil, city: nil, locality: nil, name: nil, latitude: "12.93516201597191", longitude: "77.63097871416265", created_at: "2014-03-30 14:47:03", updated_at: "2014-03-30 15:20:52", address: nil, id_location: "60f7f024d37c74f9">,
#<Location id: 9, country: nil, state: nil, city: nil, locality: nil, name: "Cafe Coffee Day", latitude: "12.93434671368444", longitude: "77.6256083701297", created_at: "2014-03-29 15:41:42", updated_at: "2014-03-29 15:41:42", address: "Mango Suites,", id_location: "8db810b6762fd784">,
#<Location id: 8, country: nil, state: nil, city: nil, locality: nil, name: "Cafe Coffee Day", latitude: "12.932626125142486", longitude: "77.62338638305664", created_at: "2014-03-29 15:31:53", updated_at: "2014-03-29 15:31:53", address: "BPCL RAJAJINAGAR,Dr.RajkumarRoad, Rajajinagar", id_location: "ff71f5a0b4de9e1b">]
location_by_where output is
[#<Location id: 7, country: nil, state: nil, city: nil, locality: nil, name: "Coffee On Canvas", latitude: "12.93516201597191", longitude: "77.63097871416265", created_at: "2014-03-29 15:20:34", updated_at: "2014-03-29 15:20:34", address: "#84, S.T.Bed Layout, 4th Block Koramangala", id_location: "cd49dfa966245b12">,
#<Location id: 8, country: nil, state: nil, city: nil, locality: nil, name: "Cafe Coffee Day", latitude: "12.932626125142486", longitude: "77.62338638305664", created_at: "2014-03-29 15:31:53", updated_at: "2014-03-29 15:31:53", address: "BPCL RAJAJINAGAR,Dr.RajkumarRoad, Rajajinagar", id_location: "ff71f5a0b4de9e1b">,
#<Location id: 9, country: nil, state: nil, city: nil, locality: nil, name: "Cafe Coffee Day", latitude: "12.93434671368444", longitude: "77.6256083701297", created_at: "2014-03-29 15:41:42", updated_at: "2014-03-29 15:41:42", address: "Mango Suites,", id_location: "8db810b6762fd784">,
#<Location id: 10, country: nil, state: nil, city: nil, locality: nil, name: nil, latitude: "12.93516201597191", longitude: "77.63097871416265", created_at: "2014-03-30 14:47:03", updated_at: "2014-03-30 15:20:52", address: nil, id_location: "60f7f024d37c74f9">]
but while using it in a join both produces different results
books = books.joins(:location).merge(locations_by_geocoder)
produces
[#<Book id: 10, created_at: "2014-03-30 14:47:03", updated_at: "2014-03-30 15:20:52">]
query syntax is
SELECT locations.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((12.9398981 - locations.latitude) * PI() / 180 / 2), 2) + COS(12.9398981 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((77.6275559 - locations.longitude) * PI() / 180 / 2), 2))) AS distance, CAST(DEGREES(ATAN2( RADIANS(locations.longitude - 77.6275559), RADIANS(locations.latitude - 12.9398981))) + 360 AS decimal) % 360 AS bearing FROM `books` INNER JOIN `locations` ON `locations`.`id` = `books`.`location_id` WHERE (locations.latitude BETWEEN 12.930904883940814 AND 12.948891316059187 AND locations.longitude BETWEEN 77.61832835502157 AND 77.63678344497843 AND 6371.0 * 2 * ASIN(SQRT(POWER(SIN((12.9398981 - locations.latitude) * PI() / 180 / 2), 2) + COS(12.9398981 * PI() / 180) * COS(locations.latitude * PI() / 180) * POWER(SIN((77.6275559 - locations.longitude) * PI() / 180 / 2), 2))) <= '1') ORDER BY distance ASC
where as
books = books.joins(:location).merge(locations_by_where)
produces
[#<Book id: 11, title: "ggn", author: "steven jobs,steve jobs", isbn_10: "1572846933", isbn_13: "1932841660", edition: "1", print: nil, publication_year: 2011, publication_month: "2011", condition: "", value: nil, status: nil, stage: nil, description: "", visits: 38, user_id: 5, prefered_place: nil, prefered_time: nil, created_at: "2014-01-01 08:13:00", updated_at: "2014-03-30 14:47:35", rating: nil, image: nil, publisher: nil, goodreads_id: nil, ext_image_url: nil, pages: nil, language_code: nil, barter_type: nil, location_id: 10, id_book: nil>]
and query syntax is
SELECT `books`.* FROM `books` INNER JOIN `locations` ON `locations`.`id` = `books`.`location_id` WHERE `locations`.`id` IN (7, 10, 9, 8)
even though the output of locations_by_where and locations_by_geocoder are same
both are ActiveRecord::Relation::ActiveRecord_Relation_Location
the issue is connected to near scope in locations.near
https://github.com/alexreisner/geocoder/issues/627#issuecomment-39048249