Using NHibernate from C# and only HQL (not SQL) in a way that is compatible with MS SQL Server 2005/2008 (and preferably Oracle).
Is there a way to write the order by clause so that nulls will sort at the end of the query results while the non-null results will be sorted in ascending order?
Based on the answer to the question referenced by nickf the answer is:
select x from MyClass x order by case when x.MyProperty is null then 1 else 0 end, x.MyProperty
I don't know if this helps or not, but there's another question asking the same thing about how to do this with MySQL.
Perhaps the same logic could be applied to HQL?
edit: this got accepted, so apparently, yes it can.
Here's the accepted answer from that question (by Bill Karwin):
SELECT * FROM myTable
WHERE ...
ORDER BY CASE WHEN myDate IS NULL THEN 1 ELSE 0 END, myDate;
At one point I just gave up and fixed the sort order in my collection class.
Since I was just moving NULLs all I had to do was peel off the nulls at the beginning of the collection and append them to the end.
With a bet of cleaver coding, it can even be done on an array.
Nevertheless, that ORDER BY CASE is a cleaver and readable trick.
Related
I am new to sql server, transitioning from mysql.
I have a complicated case statement that I would like to group on 6 whens and an else. Likely to get larger. To be able to run it, I need to copy the statement into the group by each time there is a modification. In mySql I would just group by the column number. Is there any work around for this? Making the code very ugly.
Is there going to be a performance penalty in creating a sub query for my case, then just grouping on the result field. Seems like trying to make the code more elegant will cause the query to use more resources.
Thanks
Below is a field I am grouping on. As I make a modification to the field for more edge cases, then I need to change code in up to 3 places. Makes for some very ugly code, and I need no extra help doing that myself.
dz_code = case
when isnull(dz.dz_code,'N/A') in ('GAB', 'MAB', 'N/A') and dc.howdidyouhear = 'Television' then 'Television'
when isnull(dz.dz_code,'N/A') in ('GAB', 'MAB', 'N/A') and dc.howdidyouhear in ('Other', 'N/A') then 'Other'
WHEN dz.dz_code = 'irs,irs' THEN 'irs'
when dz.dz_code like '%SDE%' THEN 'SDE'
when dz.dz_code like 'referral,' then REPLACE(dz.dz_code, 'referral','')
when charindex(',',dz.dz_code) = 4 then left(dz.dz_code,3)
else
dz.dz_code
END,
Maybe you can wrap the query in a subquery and use the alias in the select and the group by. It looks a little bulky in this example, but if you've got more complex case switches, or more than one of them, then this solution will probably much smaller and more readable.
select
CaseField
from
(select
case when 1 = 2 then
3
else 4 end as CaseField
from
YourTable t) c
group by
CaseField
This could be a simple question, but it's one I've never seen answered before. Is there a way to use an if statement's condition as its value? This would be really useful in cases where lots of calculation is done to determine if a certain condition is met and if it is, that calculation is the result.
As an example:
if ( [intense calculation] > 0, [same intense calculation], 0)
I'm interested particularly with regards to SQL, as I'm working on a report in Access right now and so can't store the result of the intense calculation in a variable.
Not sure if such a concept exists in the MS Access report world, but how about:
MAX([intense calculation], 0)
The obvious benefit of such an approach is that the calculation would only need to be done once.
One approach in most forms of SQL would be to move the main query to a sub-query, with the intense calculation column aliased and tested in the new outer query - like so:
select v.*,
case intense_calc > 0 then intense_calc else 0 end as positive_calc
from (select [intense calculation] as intense_calc,
[other columns]
from ...) as v
I need to order a table conditioned by date and i cant do it!! :(
i have a field (codigo) that if the year of the date(passed by parameter) is less than 2010 then it is composed like this : "FAC-00123-10", then i nedd to order by this "00123"...
Otherwise, if the year code is bigger than 2010, the field (Codigo) is created like this "FT 11/123" and then i need to order by this "123"
How can i do this?!
You can use a case when statement to decide what to order by, this uses a simple substring but in reality this probably isnt good enough and you may need to parse the bit you are interested in a little bit better..
select * from table order by
case when DatePart(year,#date) < 2010 then substring(codigo,4,5)
else substring(condigo,3,2) end
Ok, I have to put null values last. The query should run under Oracle and MySQL.
I've already came up with
ORDER BY
CASE WHEN some_table.ord IS NULL THEN 9999999999 ELSE some_table.ord END
I should use value > max(some_table.ord) instead of 9999999999.
I think subquery to determine this value is too ugly here.
If this was C++ I can use some macro like INT_MAX for this purpose. Can you name its cross-DBMS SQL twin?
UPDATE
the question is if can I put something .. beautiful instead of 9999999999, so that query will work both in Oracle and MySQL,
not how to put null values last
Use an extra column for the null flag:
order by
case when some_table.ord is null then 2 else 1 end ,
some_table.ord
Or, if you have enough knowledge of the values that this column can take, just hard-code a number that is larger than anything in there:
order by coalesce(some_table.ord, 9999999999)
In Oracle, it's simply
ORDER BY some_table.ord NULLS LAST
Something like the following might work:
SELECT S.VAL1, S.VAL2, S.VAL3, COALESCE(S.ORD, O.MAX_ORD+1) AS ORD
FROM SOME_TABLE S,
(SELECT MAX(ORDER) AS MAX_ORD FROM SOME_TABLE) O
WHERE S.whatever = whichever AND
S.something <> something_else
ORDER BY ORD
Not sure if MySQL allows sub-queries in the FROM list. The idea here is to avoid the use of a magic value to handle the NULL case.
Share and enjoy.
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.