Rails ID and order - ruby-on-rails-3

Rails 3 app. How would I find only records with an id of "1" and put them in DESC order? I feel like this is a simple question but I can't figure it out?

Although I do not understand why would you need to order only one record, the solution (provided that I understood) that solves your question is:
Item.where("id = 1").order("id DESC").first
# => Item Load (0.7ms) SELECT `items`.* FROM `items` WHERE id = 1 ORDER BY id DESC LIMIT 1

Related

Most recent inner query in activerecord

I have a table users:
id first_name
--------------
1 Bill
2 Denise
who read multiple books:
id book user_id read_at
---------------------------------------------------
1 Garry Potter 1 2020-1-1
2 Lord of the wrist watch 2 2020-1-1
3 90 Shades of navy 2 2020-1-2
I want to create a scope in my book model that gets me the latest book for each user. There's plenty examples of doing this with pure SQL, the problem I'm running to is creating a flexible scope that can be used with a count, inner query or any other way you would typically use a scope.
So far I have this in my book model:
def self.most_recent
inner_query = select('DISTINCT ON (user_id) *').order(:user_id, read_at: :desc)
select('*').from(inner_query, :inner_query).order('inner_query.id')
end
Which is very close to what I want. It works with a count however not in a more complicated situation.
For example if I want to get a list of users where their latest book is "Garry Potter", I try something like this:
User.where(id: Book.most_recent.where(book: 'Garry Potter').select(:user_id))
Active record gets confused and generates this SQL:
SELECT "users".* FROM "users" WHERE "users"."id" IN (SELECT "user_id", * FROM (SELECT "books"."user_id", DISTINCT ON (user_id) * FROM "books" ORDER BY "books"."user_id" ASC, "books"."read_at" DESC) inner_query WHERE "books"."book" = "Garry Potter" ORDER BY inner_query.id)
Which gives the following error:
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "DISTINCT"
Is there an elegant way to achieve this?
You can try change the method most_recent by returning a query with where:
def self.most_recent
# Select only the ids of the most recent books
inner_query = select('DISTINCT ON (user_id) books.id').order(:user_id, read_at: :desc)
# Return a where query like Book.where(id: <ids in the result set of the query above>)
where(id: inner_query)
end
# You should now be able to perform the following query
User.where(
id: Book.most_recent.where(book: 'Garry Potter').select(:user_id)
)

Phalcon Model order by item popularity (number of appearances)

I'm sure I have done something like this before, but can't find it and google not being helpful.
Using Phalcon model if possible, I want to select the items from a table whose ID appears the most - i.e. 10 most popular items ordered by popularity. Is this possible using Model::find("conditions")? I do I have to use PHQL for this?
using model::find
Model::find([
'columns' => 'id,count(id) as counter',
'group' => 'id',
'order' => 'counter DESC'
]);
PHQL:
$this->modelsManager->executeQuery('SELECT count(id) AS counter,id FROM ModelName GROUP BY id ORDER BY counter DESC');
find() does have a group clause, but I don't think it's possible to do what you want because you also need to do a count.
Talal's answer is close, but won't work if you want a list of model objects.
Something like this should work:
$Results = $this->modelsManager->executeQuery('SELECT * FROM ModelName GROUP BY id ORDER BY count(id) DESC LIMIT 10');
$Results->setHydrationMode(\Phalcon\Mvc\Model\Resultset::HYDRATE_RECORDS);
Setting the hydration mode may not be necessary, as Phalcon may default to that mode based on the fact the query is asking for *.

How to query the last N Parent rows with that had the most recent children created? in ruby

I have 2 models, Device and HealthRecord with the basic relationship of:
device has_many health_records
health_records belong_to device.
I want to get the LAST 10 devices that has the most recently created health_records.
I can get it using this, but this gets ALL of the records:
Device
.select("devices.id, MAX(health_records.id) AS latest_health_id")
.joins(:health_records)
.group("devices.id")
.order("latest_health_id DESC")
If I add .limit(10), it just gives me a Device::ActiveRecord_Relation which i cannot inspect. (when i inspect it says Invalid column name 'latest_health_id'.). Adding .first(10) does not work too.
As per the description shared below mentioned query will fetch devices of last 10 created health records.
Device
.select("devices.id")
.joins(:health_records)
.group("devices.id")
.order("health_records.created_at DESC").limit(10)
I think you can achieve your goal with the following query:
Device
.joins(:health_records)
.order('health_records.created_at DESC')
.group(:id)
.distinct
.limit(10)
This will return Device::ActiveRecord_Relation object. If you want only ids, just add pluck(:id) at the end, which will change your query from SELECT DISTINCT "devices".* to SELECT DISTINCT "devices"."id" and return Array of ids.
Here is another solution that should probably work for you (albeit untested):
Device.where(id: HealthRecord.select(:device_id)
.group(:device_id)
.order("MAX(health_records.id) DESC")
.limit(10)
)
This should result in a query similar to
SELECT
devices.*
FROM
devices
WHERE
id IN (
SELECT
health_records.device_id
FROM
health_records
GROUP BY
health_records.device_id
ORDER BY
MAX(health_records.id) DESC
LIMIT 10 OFFSET 0
)
For now I ended up using either of this two:
Device
.select("devices.id, MAX(health_records.id) AS latest_health_id")
.joins(:health_records)
.group("devices.id")
.order("latest_health_id DESC")
.map(&:id).first(10)
Device
.joins(:health_records)
.order('health_records.created_at DESC')
.pluck(:id).uniq.first(10)
it gives me an array of the last 10 device ids that most recently created a health_record

How to order by largest amount of identical entries with Rails?

I have a survey where users can post answers and since the answers are being saved in the db as a foreign key for each question, I'd like to know which answer got the highest rating.
So if the DB looks somewhat like this:
answer_id
1
1
2
how can I find that the answer with an id of 1 was selected more times than the one with an id of 2 ?
EDIT
So far I've done this:
#question = AnswerContainer.where(user_id: params[:user_id]) which lists the things a given user has voted for, but, obviously, that's not what I need.
you could try:
YourModel.group(:answer_id).count
for your example return something like: {1 => 2, 2 => 1}
You can do group by and then sort
Select answer_id, count(*) as maxsel
From poll
Group by answer_id
Order by maxsel desc
As stated in rails documentation (http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html) when you use group with count, active record "returns a Hash whose keys represent the aggregated column, and the values are the respective amounts"
Person.group(:city).count
# => { 'Rome' => 5, 'Paris' => 3 }

ZF2 how to avoid sql query limit to add quotes in subquery

I'm trying to set up a subquery in ZendFramework 2 and I got an issue with the limit function for a Select object. Whatever I do, numeric value is put between quotes and makes my query fails : I should get LIMIT 1 and instead I get LIMIT '1'.
Seems this is not the first time this issue has been encountered, I saw some have asked about this issue before (like 8 months ago) but without getting any proper answer.
I also saw this issue has been marker as resolved in 2012 (https://github.com/zendframework/zf2/pull/2775) so I really don't understand what's happening there.
Here's my code in ZF2 :
$resultSet = $this->tableGateway->select( function (Select $select) use ($params) {
$sub = new Select();
$sub->from(array('temp' => 'scores'))
->columns(array(new \Zend\Db\Sql\Expression("id AS id")))
->where(array('temp.glitch' => array('None', 'Glitch')))
->where('temp.zone=scores.zone')
->order('temp.multi DESC, temp.score DESC')
->limit(1);
$select->join('players', 'player=players.id', array('player_name' => 'name', 'player_url' => 'name_url'))
->join('countries', 'players.country=countries.id', array('country_name' => 'name', 'country_iso' => 'iso'))
->join('cars', 'car=cars.id', array('car_name' => 'name'), 'left')
->join('zones', 'zone=zones.id', array('zone_name' => 'name'));
$select->where(array('scores.id' => $sub));
$select->order('scores.zone ASC');
print_r($select->getSqlString());
});
This should render the following query (which I get right except LIMIT '1' instead of LIMIT 1) :
SELECT "scores".*, "players"."name" AS "player_name", "players"."name_url" AS "player_url", "countries"."name" AS "country_name", "countries"."iso" AS "country_iso", "cars"."name" AS "car_name", "zones"."name" AS "zone_name"
FROM "scores" INNER JOIN "players" ON "player"="players"."id"
INNER JOIN "countries" ON "players"."country"="countries"."id"
LEFT JOIN "cars" ON "car"="cars"."id"
INNER JOIN "zones" ON "zone"="zones"."id"
WHERE "scores"."id" = (SELECT id AS id FROM "scores" AS "temp" WHERE "temp"."glitch" IN ('None', 'Glitch')
AND temp.zone=scores.zone ORDER BY "temp"."multi" DESC, "temp"."score" DESC LIMIT 1)
ORDER BY "scores"."zone" ASC
Since this doesn't seem to work this way, is there another way I could proceed to get my limit (using Mysql 5 database) ?
EDIT :
Thanks for your help. Finally I figured out a way to get things done the way I want and to remove the quotes by simply remove the subquery construction and to write it directly in the where function :
$select->where('scores.id = (SELECT id FROM scores AS lookup WHERE lookup.zone = scores.zone ORDER BY multi DESC , score DESC LIMIT 1)');
Although I can continue my dev with this, I feel more like using a poor trick to get rid of this issue and so I will let this question unanswered until someone comes with a real solution there.
Anyway there might be no solution at all, since it might be an issue in ZF2 core itself.
Change the line -
$select->where(array('scores.id' => $sub));
with
$select->where(array('scores.id' => new \Zend\Db\Sql\Expression("({$sub->getSqlString($this->tableGateway->adapter->getPlatform())})"));
Try with just above change.
And if it still doesn't work then make changes to the core Select class file located at -
PROJECT_FOLDER/vendor/zendframework/zendframework/library/Zend/Db/Sql/Select.php
Line No. 921 -
Change $sql = $platform->quoteValue($limit); with $sql = $limit;
Line No. 940 -
Change return array($platform->quoteValue($offset)); with return array($offset);
I have come across the issue from github and wondered as why it is still not working with the latest ZF2 files. I know the solution given above doesn't look like the proper one but I had to somehow make it work. I have tried it and it works.
Its only a quick fix before the actual solution comes into picture.