Sorting null-data last in database query - sql

i have an application where i order make a query to my database with an ORDER BY clause, it will order them in alphabetical order. i only have one small problem, it happens fairly often that one of the strings that the query is ordering by contains nothing (string="") when sorting in alphabetical order these get populated at the top of the list infront om a,b,c... i plain and simple dont want this. after a lot of googling i found on an oracle forum that i should change the SORT BY part of the query to "SORT BY xxx ASC NULLS LAST" this caused a fatal error when querying.
how shall i go by fixing this seemingly small issue?
here is my query statement as is today.
public Cursor fetchAllDatesByTag() {
return mdiktationsDb.rawQuery("SELECT " + KEY_DATEID + "," +" " + KEY_DATE + "," + " " + KEY_TIME + "," + " " + KEY_DICTTAG + "," + " " + KEY_DICTLISTIMAGE + " FROM " + DATABASE_TABLE + " ORDER BY " + KEY_DICTTAG + " ASC", null);
}

use a CASE equivalent in your ORDER BY
Like
ORDER BY CASE column WHEN NULL THEN 1 ELSE 0 END, column
so then it orders by the nulls first, then the actual column.
EDIT: And if you want to filter ""s (blank strings) or whatever else, you can employ this same method... assigning a numeric value to it and sorting before the alphabetizing.
EDIT2:
....+ " ORDER BY CASE " + KEY_DICTTAG + "WHEN NULL THEN 1 ELSE 0 END, " + KEY_DICTTAG + " ASC"

Solution one:
ORDER BY foo NULLS LAST
and
ORDER BY foo NULLS FIRST
But this seems to work only with numeric columns :(
Solution two:
ORDER BY IF(ISNULL(my_field),1,0),my_field
which will create a "fake"-column that just consist 0 or 1, depending on if my_field is null or not null, and sort on that. the fields that are not null will come first. in a second step, SQL will sort my_field, like before.

How about adding a WHERE field IS NOT NULL. This way you shouldn't get any null values back from your query.

Related

Using sub-select in FROM clause inside JPA #NamedQuery

In my app I need to use #NamedQuery to find the type of the most frequent operation assigned to specific account
#Entity
#Table(name="\"ACCOUNTOPERATION\"")
#NamedQuery(name="AccountOperation.findTypeOfMostFrequentOperation", query="" +
"SELECT ao.type from AccountOperation ao WHERE ao.account.id = ?1 " +
"GROUP BY ao.type HAVING COUNT(ao) = (" +
"SELECT MAX(typeCountQuery.typeCount) " +
"FROM (" +
"SELECT COUNT(aop) as typeCount " +
"FROM AccountOperation aop WHERE aop.account.id = ?1 GROUP BY aop.type" +
") as typeCountQuery" +
")"
)
public class AccountOperation {
#ManyToOne
private Account account;
private BigDecimal amount;
private OperationType type;
...
Right after FROM clause at '(' character, which begins typeCountQuery's body I'm getting
')', ',', GROUP, HAVING, IN, WHERE or identifier expected, got '('
I've read that JPA does not support sub-selects in the FROM clause, so is there any way to rewrite SQL code to still use it in #NamedQuery?
I'm using IntelliJ IDE with H2 DB and with eclipselink and javax.persistence in dependencies.
Link to source
In JPQL, you cannot use subqueries. To resolve this issue, you need to use some keywords like ALL, ANY, which work similiar.
So in your situation it could be:
#NamedQuery(name="AccountOperation.findTypeOfMostFrequentOperation", query="" +
"SELECT ao.type from AccountOperation ao WHERE ao.account.id = ?1 " +
"GROUP BY ao.type HAVING COUNT(ao) >= ALL (" +
"SELECT COUNT(aop) as typeCount " +
"FROM AccountOperation aop WHERE aop.account.id = ?1 GROUP BY aop.type)"
The type with a highest count returns the following query
select type
from AccountOperation
where id = ?
group by type
order by count(*) desc
fetch first 1 ROWS only
You should be anyway avare of the existence of ties, i.e. more types with the identical maximal count and should make some thought how to handle them.
I.e. in Oracle you may say fetch first 1 ROWS WITH TIES to get all the types with tha maximal count.

Sql Case expression in JPA criteria update

I have a named query :
"UPDATE student SET student.marks = " +
" CASE WHEN student.name in :" + nameListOne +
" THEN 10 ELSE marks " +
" END , student.class = 6 WHERE student.name in :" + namelistOneAndTwo
how can i achieve this using criteria update.
This is just a example i want to understand how case expression can be used in criteria update.
Might be easier just to have two updates. Not sure what "nameListOne" is, I'm assuming this is some parameter in a dynamic SQL query string.
UPDATE student
SET marks = 10
WHERE name IN nameListOne;
UPDATE student
SET class = 6
WHERE name IN nameListOneAndTwo;
There's some value in keeping things simple and intuitive.

Select a record with the largest sum of fields (Access 2010)

I would like to select a record from a table based on the field “labcode” specified by the user on a form. There could be multiple records associated with each “labcode” and I would like to select a record that has the highest sum of 10 corresponding fields in the “tblDSA". Fields are named as follows: “A1_MFI”, “A2_MFI”, “C1_MFI”, "C2_MFI", "DR1_MFI", "DR2_MFI"…)
All 10 fields are in 'text' format and sometimes contains a number, text or are left blank. I would only like to sum up records that contain a number in that field. Do I need to create a new field in “tblDSA” that holds the total score or should I avoid storing calculating values in the table?
Dim SQL As String
Dim db As DAO.Database
Dim tblDSA As DAO.Recordset
Set db = CurrentDb
Set tblDSA = db.OpenRecordset("tblDSA")
SQL = "SELECT * Nz((Val[A1_MFI])) + Nz((Val[A2_MFI])) + Nz((Val[B1_MFI])) + Nz((Val[B2_MFI])) + Nz((Val[C1_MFI])) + Nz((Val[C2_MFI])) + Nz((Val[DR1_MFI]))+ Nz((Val[DR2_MFI])) + Nz((Val[DQB1_MFI] + Nz((Val[DQB2_MFI]))as TotalScore FROM tblDSA WHERE [LABCODE] = " & Me.tbLabcode.Value & " ORDER BY TotalScore DESC "
Debug.Print SQL
Set rs = db.OpenRecordset(SQL)
The SQL above contains a syntax error (missing operator), therefore, I can't test it. I'm not sure what is missing?
Nz() is for skipping blank records and Val() is to convert each text field into value. Please let me know if this is a correct approach or I need to do something else? Thanks
Okay, after much back and forth, here is the final result that works for this particular problem:
SELECT TOP 1 *, (Nz(Val(IIf([A1_MFI] Is Null, 0, [A1_MFI]))) + Nz(Val(IIf([A2_MFI] Is Null, 0, [A2_MFI]))) + ...) AS TotalScore
FROM tblDSA
WHERE [LABCODE] = 57
ORDER BY (Nz(Val(IIf([A1_MFI] Is Null, 0, [A1_MFI]))) + Nz(Val(IIf([A2_MFI] Is Null, 0, [A2_MFI]))) + ...) DESC
I thought Access allowed field aliases in the ORDER BY, but it doesn't seem to do that any more, if it did at all.
It looks like you two things
you didn't have a comman after "SELECT *"
missing two brackets in one of your NZ statements
#PhillipXT pointed out the first - and by using his second suggestion, I think the SQL compiler would have pinpointed the missing brackets for you.
Try this with a copy / paste
SQL = "SELECT *, Nz((Val[A1_MFI])) + Nz((Val[A2_MFI])) + Nz((Val[B1_MFI])) + _
Nz((Val[B2_MFI])) + Nz((Val[C1_MFI])) + Nz((Val[C2_MFI])) + Nz((Val[DR1_MFI])) + _
Nz((Val[DR2_MFI])) + Nz((Val[DQB1_MFI])) + Nz((Val[DQB2_MFI])) AS TotalScore _
FROM tblDSA _
WHERE [LABCODE] = " & Me.tbLabcode.Value & _
" ORDER BY TotalScore DESC "

My C# SQL Select statement is not picking up any records in my table

I have 4 records in my SQL table that and I'm doing a SQL select statement to select records based on a certain criteria but I'm not picking any records up. Can someone please help?
Here is my SELECT statement:
string Sql = "";
Sql = #"SELECT * FROM " + _dtlName + "
WHERE Shipper_No = '" + sidNo + "'
AND Job_Code != '" + "R" + "'";
I have 3 records that have a Null for Job_Code and 1 record that has an R.
Based on that, I should pickup the 3 records with the NULL Job_Code but it returns 0 records.
I suspect the problem is that a comparison between any non-null value and a null value doesn't return a value of true or false, but null. So your query should probably be:
string sql = "SELECT * FROM " + _dtlName + " WHERE Shipper_No = #ShipperNo " +
"AND (Job_Code IS NULL OR Job_Code != 'R')";
(Note that I've extracted a parameter for Shipper_No - you shouldn't be including values directly in your SQL like that. Obviously you'll need to then set the parameter value in the SQL command.)
Also note that <> is more common in SQL to represent "not equal to", but I believe T-SQL allows either form.
Try,
Sql = #"SELECT * FROM " + _dtlName + " WHERE Shipper_No = '" + sidNo + "' AND Job_Code NOT IN ('R')";
I think your query should be more like this since you want to select the NULL values.
string Sql = String.Format("SELECT * " +
"FROM {0} " +
"WHERE Shipper_No = {1} AND " +
" Job_Code IS NULL",
_dtlName, sidNo)

DELETE FROM table WHERE var = value does not remove entries

So I fetched some data from a mdb file in c# via
"SELECT * FROM " + listBox1.GetItemText(listBox1.SelectedItem) + " WHERE Note = '" + listBox2.GetItemText(listBox2.SelectedItem).Replace("'","\'") + "'";
which selects the right data, here it is
SELECT * FROM Main WHERE Note ='Hello'
The mdb data structure looks like this being plotted as a CSV-file:
"Record ID";Status;Placement;Private;Category;Note;Blob
14341665;4;2147483647;True;3;"""Hello"" - Neues
But when I try to remove entries with
"DELETE FROM " + listBox1.GetItemText(listBox1.SelectedItem) + " WHERE \"Record ID\" LIKE '" + dr[0] + "';";
or
"DELETE FROM " + listBox1.GetItemText(listBox1.SelectedItem) + " WHERE \"Record ID\" = '" + dr[0] + "';";
which looks like for instance
DELETE FROM Main WHERE "Record ID" LIKE '14341665';
The entries just stay there. I can rerun the select command even restart my application, the mdb is not changed.
Is record ID a numeric field? If so, lose the quotes.
DELETE FROM Main WHERE [Record ID] = 14341665;
Note that spaces in field (column) names will always be a problem. Such columns names have to be enclosed in square brackets, as do columns named with reserved words.
The record id is numeric, so don't put apostrophes around it:
"DELETE FROM " + listBox1.GetItemText(listBox1.SelectedItem) + " WHERE \"Record ID\" = " + dr[0]
Note: You should avoid using select * in production code, you should specify the data that you want returned. Also, you should use parameterised queries instead of concatenating values into the query.
if i remember correctly, "like" only works on string data, please check the data type of Record ID.
If Record ID is numeric, you may want to use database's conversion function to convert it into string before filtering using "like".
btw, remember to make sure that dr[0] is properly escaped.