Get the rank of an entry in mysql - mysql

I'm trying to get the rank of an activerecord object based on the number of votes its currently received. In my object model, I have a method 'rank' defined as:
Object.count(:conditions => ['votes > (?)', self.votes], :distinct => true) + 1
That returns the rank. However, elsewhere in my program I have found that I actually need to get this in the mysql query itself. I wanted to try to do something like below:
Object.select('id, votes, (SELECT COUNT(DISTINCT "objects"."id")
FROM "objects"
WHERE "objects"."votes" > votes) AS rank').limit(10)
However, I dont know how to do the 'objects.votes > votes' part. I need to replace '> votes', with some reference to itself. Not sure if that's clear. Any ideas?

I will guess that you mean, how do you pass self.votes from rails to the SQL query?
You can do this:
Object.where("votes > ?",self.votes)
So to pass self.votes to your query:
Object.select('id, votes, (SELECT COUNT(DISTINCT "objects"."id")
FROM "objects"
WHERE "objects"."votes" > ?) AS rank',self.votes).limit(10)

Related

where not in select from db

I'm trying to figure out why this code doesn't work; i'm trying to select "upgrades" from the database that the user doesn't already have. I've done it two ways
This Way:
SELECT id, name, cost, prereq, nullif FROM upgrades WHERE NOT IN (Select upgrade_id FROM user_upgrades WHERE uid = :uid);
and this way:
SELECT id, name, cost, prereq, nullif FROM upgrades WHERE NOT IN (:ID)
in which the :ID tag isa list of user upgrades pulled through a function in PHP. Neither one of these codes are working--they do not show any results whats so ever.
You forgot the attribute in the condition after WHERE:
WHERE "MISSING ATTRIBUTE" NOT IN ...

mysql search for category from serialized array

I have a table 'users_category'
'users_category' : id, prefix, name
and table 'users'
'users' : categories, etc...
where users.categories is an array of users_category.id ids
User can be part of any category, if I stored the array of categories they are part of as a serialized array, how can I run a query to check if they are part of 'category x'
Ex:
SELECT users.*, users_category.* FROM 'users', 'users_category' WHERE users.categories='category x' AND users_category.id = 'category x'
I can't run a 'LIKE' command because the users.categories is serialized. Is their any way to search within the serialized data. Also I know that the above query may have errors
Even though normalizing the table structure is a better way to move forward but if adopting that route is not optimal at this point then you may try this query:
SELECT u.*, uc.*
FROM users u, users_category uc
WHERE uc.name='X' AND FIND_IN_SET(uc.id, u.categories)
It uses mysql function FIND_IN_SET().
Working demo available at: http://sqlfiddle.com/#!2/7f392/3

Refine Query Results from MySQL Database

I have the following query:
SELECT routes.route_date, time_slots.name, time_slots.openings, time_slots.appointments
FROM routes
INNER JOIN time_slots ON routes.route_id = time_slots.route_id
WHERE route_date
BETWEEN 20140109
AND 20140115
AND time_slots.openings > time_slots.appointments
ORDER BY route_date, name
This works just fine and will produce the following results:
What I want to do is only return one name per date. So the 9th, name = 1, would only have 1 result, rather than 2, as it currently does.
UPDATE: See the SQLFIDDLE for different type of solutions here: http://sqlfiddle.com/#!2/9ac65b/6
Will it solve your request if you use...
SELECT DISTINCT routes.route_date...your query... ?
It depends if you know that your rows always will have the same values, for same date/name.
Otherwise use group by...
(which I think suits your request best)
SELECT routes.route_date, time_slots.name, sum(time_slots.openings), sum(time_slots.appointments)
FROM routes
INNER JOIN time_slots ON routes.route_id = time_slots.route_id
WHERE route_date
BETWEEN 20140109
AND 20140115
AND time_slots.openings > time_slots.appointments
group by routes.route_date, time_slots.name
ORDER BY route_date, name
(i did a sum for the openings and appointments, you could do min, max, count, etc. Pick the one that fits your requirements best!)
You need to figure out which "name" you want when there are several for the same date.
Then you can group by date and select the right "name" by using an aggregate function like COUNT, MAX, etc.
I can't help you more if you don't explain your rule for picking one.

Using Django Count() with conditional lookup types

So I'm trying to aggregate exam data, and because the database lives on another server I'm trying to reduce this to as few database calls as possible.
I have this model (whose corresponding table is in a mySQL database if that matters):
class Exam(models.Model):
submitted = models.BooleanField(default=False)
score = models.DecimalField(default=Decimal(0))
And this query:
>>> exam_models.Exam.objects\
... .using("exam_datebase")\
... .aggregate(average=Avg("score"),
... total=Count("submitted"))
{'average': 22.251082, 'total': 231}
What I'm looking for is a way to also retrieve the number of passed exams, something along the lines of:
>>> exam_models.Exam.objects\
... .using("exam_datebase")\
... .aggregate(average=Avg("score"),
... total=Count("submitted"))
... passed=Count("score__gte=80"))
{'average': 22.251082, 'total': 231, 'passed': 42}
I know I can just send another query using .filter(score__gte=80).count(), but I was really hoping to get both the total count and the passing count on the same aggregate. Any ideas?
You are either going to need two queries, or do the aggregation manually.
To see why, let's consider the underlying SQL that Django generates and uses to query the database.
Exam.objects.aggregate(average=Avg("score"), total=Count("submitted"))
roughly translates to
SELECT AVG(score), COUNT(submitted)
FROM exam
The "Count" part of the aggregate is applying to the SELECT clause in the underlying sql query. But if we want to include only scores greater than some value, the SQL query would need to look something like this:
SELECT AVG(score), COUNT(submitted)
FROM exam
WHERE score > 80
Filtering Exams with a particular "score" is applies to the WHERE or HAVING clause of the underlying SQL statement.
Unfortunately, there is not really a way to combine these two things. So, you are stuck doing two queries.
Having said all that, if you REALLY want to do a single query, one option is to just do the aggregation in your python code:
exams = Exam.objects.all()
total_score = 0
total_submitted = 0
passed = 0
for exam in exams:
total_score += exam.score
if exam.submitted:
total_submitted += 1
if exam.score >= 80:
passed += 1
exam_aggregates = {
'average': total_score / len(exams),
'submitted': total_submitted,
'passed': passed,
}

Doctrine 2 does not recognize SELECT on the FROM clause

I have a SQL query I would like to use in Doctrine2.
My query, goes to the dabatase, does a GROUP BY user state and COUNT the number of users per state.
Then I'm trying to join a table to COUNT all users and make a percent for every state.
return $this->getEntityManager()
->createQuery("
SELECT COUNT(u.id) as total,
(100*(COUNT( u.id ) / total_users.total)) as percent
FROM UserBundle:User u,
(SELECT COUNT(*) as total
FROM UserBundle:User) as total_users
LEFT JOIN u.idUserEstado ue
GROUP BY u.idUserEstado")
->getResult();
The problem is, when I run the Doctrine2 query I get an exception:
[Semantical Error] line 0, col 397 near
'(SELECT COUNT(': Error: Class '(' is not defined.
Doctrine does not recognize that SELECT on the FROM clause.
Select on the from clause are not handled by doctrine 2
There is a closed (and not accepted) feature request on doctrine's jira : http://www.doctrine-project.org/jira/browse/DDC-2793
DQL is about querying objects. Supporting subselects in the FROM
clause means that the DQL parser is not able to build the result set
mapping anymore (as the fields returned by the subquery may not match
the object anymore). This is why it cannot be supported (supporting it
only for the case you run the query without the hydration is a no-go
IMO as it would mean that the query parsing needs to be dependant of
the execution mode).
(SELECT COUNT( * ) as total FROM UserBundle:User) as total_users
COUNT(*) may not exists in DQL. Try COUNT(u.id), the results will be the same. You also have the possibility to try this in an EntityRepository :
$qb->select(array(
'count(u.id) as total',
'(100*(count(u.id)/total_users.total)) as percent',
'select count(u.id) as total_users) as total_users'))
->from('UserBundle:User')
->leftJoin('u.idUserEstado','ue')
->groupBy('u.idUserEstado');
return $qb->getQuery()->getResult();
Source: Google UserGroup issue
the
... FROM UserBundle:User u, ...
is strange. Maybe it can't find the class User.