Rails Order by SQL - sql

I have a TraitQuestion model that have a number of traits or answers - each of which has a value such as 1, 2, 3, or -3105 (for none of the above). I can't change these values because they are required for an external API.
I'd like to order them by the value, but when I do that, the answer with -3105 shows up at the top even though it says "None of the above":
Answer 4 = -3105
Answer 1 = 1
Answer 2 = 2
Answer 3 = 3
Any idea on how we could order this so that it's
1
2
3
-3105?
I'm pretty new to SQL but it seems like I should be able to do something like this:
#trait_question.traits.order('CASE WHEN value AS int > 0 then 1 ELSE 0 END')
But that doesn't work. Any ideas how I can adjust the order call SQL such that it would order them in the correct order?
EDIT:
This is Postgresql 9.4.1 via Amazon AWS

I don't know if this will work for you or not but try this:
#trait_question.traits.order('ABS(value)')
The ABS will change the negative value to positive hence taking the absolute value each time. If your database field is string then you can do it like this as suggested by Tom which worked for him:
#trait_question.traits.order('ABS(CAST(value AS int))')

Hey you can try this way
#trait_question.traits.order("CASE WHEN (value AS integer > 0) THEN value ELSE (value As integer)*(-1) END")
Other wise use
#trait_question.traits.order("abs(value AS integer)")

I'm not sure what exactly you try to do. and I can't make a normal comment, but I'll give it a try.
can you go to your projekt folder run rails dbconsole
and execute
SELECT * FROM traitquestions ORDER BY value
This schould give you all entries ordered by the value, if you only want all possible values, run
SELECT value FROM traitquestions ORDER BY value GROUP BY value
if it works you can just create a method
def get_values
find_by_sql "SELECT value FROM traitquestions ORDER BY value GROUP BY value"
end
and call this from the controller (or where ever you want)

Related

accumulating a value in SQL

I am trying to accumulate a value when a certain condition exists such as
If statusCode = 0
then add 1 to a value.
I am trying to show the number of successful records as defined by the statusCode.
There must be a better way to do this.
Thanks
Select count(1) from yourTable where statusCode=0

Countif query in access

I am trying to run a query that calculate with a countif function but I am having trouble with it. I have used the count and the iif functions in the builder but I think something weird is going on. I am trying to count the number of times a certain value occurs in a column so I do not want a specific value to equal to if that's possible?
Thanks!
To count the number of times a value appears you can use something like.
If you want to know how many times each value appears just omit the WHERE clause (without a sample of data I've used a table in the database I'm working on).
SELECT ProcessID,
COUNT(ProcessID)
FROM tbl_PrimaryData_Step1
WHERE ProcessID = 4
GROUP BY ProcessID
if you need just the value you can use:
SELECT COUNT(ProcessID)
FROM tbl_PrimaryData_Step1
WHERE ProcessID = 4
GROUP BY ProcessID
Another way is:
SELECT DCOUNT("ProcessID","tbl_PrimaryData_Step1","ProcessID = 4")
Edit:
In reply to your comment on your original post this SQL will give the result you're after:
SELECT Concatenate,
COUNT(Concatenate)
FROM MyTable
GROUP BY Concatenate

Checking Range in Comma Separated Values [SQL Server 2008]

I have a table with following structure
ID FirstName LastName CollectedNumbers
1 A B 10,11,15,55
2 C D 101,132,111
I want a boolean value based on CollectedNumber Range. e.g. If CollectedNumbers are between 1 and 100 then True if Over 100 then False. Can anyone Suggest what would be best way to accomplish this. Collected Numbers won't be sorted always.
It so happens that you have a pretty simple way to see if values are 100 or over in the list. If such a value exists, then there are at least three characters between the commas. If the numbers are never more than 999, you could do:
select (case when ','+CollectedNumbers+',' not like '%,[0-9][0-9][0-9]%' then 1
else 0
end) as booleanflag
This happens to work for the break point of 100. It is obviously not a general solution. The best solution would be to use a junction table with one row per id and CollectedNumber.
Just make a function, which will return true/False, in the database which will convert the string values(10,11,15,55) into a table and call that function in the Selection of the Query like this
Select
ID, FirstName, LastName,
dbo.fncCollectedNumbersResult(stringvalue) as Result
from yourTableName
I think the easiest you can do is build a C# function and use the builtin sqlclr to load it as a custom function you can then call.
Inside the C# function, you can then sort your numbers and make simple logic to return your true/false.

Returning the first X records in a postgresql query with a unique field

Ok so I'm having a bit of a learning moment here and after figuring out A way to get this to work, I'm curious if anyone with a bit more postgres experience could help me figure out a way to do this without doing a whole lotta behind the scene rails stuff (or doing a single query for each item i'm trying to get)... now for an explaination:
Say I have 1000 records, we'll call them "Instances", in the database that have these fields:
id
user_id
other_id
I want to create a method that I can call that pulls in 10 instances that all have a unique other_id field, in plain english (I realize this won't work :) ):
Select * from instances where user_id = 3 and other_id is unique limit 10
So instead of pulling in an array of 10 instances where user_id is 3 and you can get multiple instances with the other_id is 5, I want to be able to run a map function on those 10 instances and get back something like [1,2,3,4,5,6,7,8,9,10].
In theory, I can probably do one of two things currently, though I'm trying to avoid them:
Store an array of id's and do individual calls making sure the next call says "not in this array". The problem here is I'm doing 10 individual db queries.
Pull in a large chunk of say, 50 instances and sorting through them in ruby-land to find 10 unique ones. This wouldn't allow me to take advantage of any optimizations already done in the database and I'd also run the risk of doing a query for 50 items that don't have 10 unique other_id's and I'd be stuck with those unless I did another query.
Anyways, hoping someone may be able to tell me I'm overlooking an easy option :) I know this is kind of optimizing before it's really needed but this function is going to be run over and over and over again so I figure it's not a waste of time right now.
For the record, I'm using Ruby 1.9.3, Rails 3.2.13, and Postgresql (Heroku)
Thanks!
EDIT: Just wanted to give an example of a function that technically DOES work (and is number 1 above)
def getInstances(limit, user)
out_of_instances = false
available = []
other_ids = [-1] # added -1 to avoid submitting a NULL query
until other_ids.length == limit || out_of_instances == true
instance = Instance.where("user_id IS ? AND other_id <> ALL (ARRAY[?])", user.id, other_ids).limit(1)
if instance != []
available << instance.first
other_ids << instance.first.other_id
else
out_of_instances = true
end
end
end
And you would run:
getInstances(10, current_user)
While this works, it's not ideal because it's leading to 10 separate queries every time it's called :(
In a single SQL query, it can be achieved easily with SELECT DISTINCT ON... which is a PostgreSQL-specific feature.
See http://www.postgresql.org/docs/current/static/sql-select.html
SELECT DISTINCT ON ( expression [, ...] ) keeps only the first row of
each set of rows where the given expressions evaluate to equal. The
DISTINCT ON expressions are interpreted using the same rules as for
ORDER BY (see above). Note that the "first row" of each set is
unpredictable unless ORDER BY is used to ensure that the desired row
appears first
With your example:
SELECT DISTINCT ON (other_id) *
FROM instances
WHERE user_id = 3
ORDER BY other_id LIMIT 10

Using boolean expression in order by clause

I have an order by clause that looks like:
( user_id <> ? ), rating DESC, title
Where ? is replaced with the current user's id.
On postgresql this gives me the ordering I'm looking for i.e. by current user, then highest rating, then title (alphabetically).
However on MySQL I get an unclear order current user is neither first nor last, nor is it by rating or title.
Is my only option for cross database compatibility to replace this quick and dirty boolean expression with a CASE WHEN .. THEN .. ELSE .. END statement?
Edit: Thanks all for the assistance, it is as correctly pointed out by Chaos and Chad Birch the case that the problem lies elsewhere (specifically that I'm using the results of the above query as input into the next - then acting surprised that the order of the first is lost ;)
MySQL has no real notion of booleans, and simply maps TRUE and FALSE to the numeric values 1 and 0 repectively.
In this case user_id <> ? will return 0 for the majority of the rows in your table and 1 for the other rows. The default sort order is ASC, meaning in all likelihood the rows you want are at the bottom of your result set (0/FALSE come before 1/TRUE). Try modifying your query to accommodate this.
( user_id <> ? ) DESC, rating DESC, title
Assuming this is indeed the issue, cross-database compatibility can be achieved with ease.
IF(user = ?, 0, 1), rating DESC, title
You could try doing a
select (user_id <> ?), user_id
to see that you are getting the right true/false values showing up.
I tested several variations on this in mysql and they all worked correctly (the way you're expecting). I suppose your problem has to be somewhere other than the query. To verify for yourself, I suggest running an equivalent query directly from mysql client.