How to keep type safety for an aliased column in Jooq? - alias

Let's say I want to select the max value of a specific field:
getContext().select( ..., //several fields
DSL.max(MY_TABLE.SCORE).as("max_score"))
.from(MY_TABLE)
.where(...)
.groupBy(...);
I fetch the results, and now I want to get the values of a specific record, so I do:
Integer maxScore = (Integer) record.get("max_score");
This is working just fine, but I have 2 issues with this approach:
Type safety is lost - I must cast the value to Integer.
Although this field will never be null, Jooq is not aware of this. If I define maxScore as int instead of Integer, I get a warning on this line:
Unboxing of 'record.get("max_score")' may produce 'NullPointerException'.
For table's "not-null" fields, I don't get this warning.
Is there a way to overcome these issues?

Type safety is lost - I must cast the value to Integer.
You can just assign it to a local variable:
Field<Integer> maxScore = max(MY_TABLE.SCORE).as("max_score");
Use it like this:
.select(..., maxScore)
.from(...)
And then:
record.get(maxScore);
If I define maxScore as int instead of Integer, I get a warning [...]
The warning is likely to go away with the above approach. While Record.get(String) returns #Nullable Object, Record.get(Field<T>) just returns T (inheriting T's nullability, which is likely to be unspecified).

Related

Checking against value in a STRING_TABLE in a WHERE clause

I have a procedure with the parameter IT_ATINN:
IMPORTING
REFERENCE(IT_ATINN) TYPE STRING_TABLE
IT_ATINN contains a list of characteristics.
I have the following code:
LOOP AT values_tab INTO DATA(value).
SELECT ( #value-INSTANCE ) AS CUOBJ
FROM IBSYMBOL
WHERE SYMBOL_ID = #value-SYMBOL_ID
AND ATINN ??? "<======== HERE ???
APPENDING TABLE #DATA(ibsymbol_tab).
ENDLOOP.
How can I check if ATINN (in the WHERE clause) is equal to any entry in IT_ATINN?
To achieve what you want (and I assume you want dynamic SELECT fields) you cannot use inline declarations here, both in LOOP and in SELECT:
The structure of the results set must be statically identifiable. The SELECT list and the FROM clause must be specified statically and host variables in the SELECT list must not be generic.
So either you use inline or use dynamics, not both.
Here is the snippet that illustrates Sandra good suggestion:
TYPES: BEGIN OF ty_value_tab,
instance TYPE char18,
symbol_id TYPE id,
END OF ty_value_tab.
DATA: it_atinn TYPE string_table.
DATA: rt_atinn TYPE RANGE OF atinn,
value TYPE ty_value_tab,
values_tab TYPE RANGE OF ty_value_tab,
ibsymbol_tab TYPE TABLE OF ibsymbol.
rt_atinn = VALUE #( FOR value_atinn IN it_atinn ( sign = 'I' option = 'EQ' low = value_atinn ) ).
APPEND VALUE ty_value_tab( instance = 'ATWRT' ) TO values_tab.
LOOP AT values_tab INTO value.
SELECT (value-instance)
FROM ibsymbol
WHERE symbol_id = #value-symbol_id
AND atinn IN #rt_atinn
APPENDING CORRESPONDING FIELDS OF TABLE #ibsymbol_tab.
ENDLOOP.
Overall, it makes no sense select ibsymbol in loop, 'cause it has only 8 fields, so you can easily collect all necessary fields from values_tab and pass them as dynamic fieldstring.
If you wanna use alias CUOBJ for your dynamic field you should add it like this:
LOOP AT values_tab INTO value.
DATA(aliased_value) = value-instance && ` AS cuobj `.
SELECT (aliased_value)
...
Remember, that your alias should exists among ibsymbol fields, otherwise in case of static ibsymbol_tab declaration this statement will throw a short dump.

Force FsCheck to generate NonEmptyString for discriminating union fields of type string

I'm trying to achieve the following behaviour with FsCheck: I'd like to create a generator that will generate a instance of MyUnion type, with every string field being non-null/empty.
type MyNestedUnion =
| X of string
| Y of int * string
type MyUnion =
| A of int * int * string * string
| B of MyNestedUnion
My 'real' type is much larger/deeper than the MyUnion, and FsCheck is able to generate a instance without any problem, but the string fields of the union cases are sometimes empty. (For example it might generate B (Y (123, "")))
Perhaps there's some obvious way of combining FsCheck's NonEmptyString and its support for generating arbitrary union types that I'm missing?
Any tips/pointers in the right direction greatly appreciated.
Thanks!
This goes against the grain of property based testing (in that you explicitly prevent valid test cases from being generated), but you could wire up the non-empty string generator to be used for all strings:
type Alt =
static member NonEmptyString () : Arbitrary<string> =
Arb.Default.NonEmptyString()
|> Arb.convert
(fun (nes : NonEmptyString) -> nes.Get)
NonEmptyString.NonEmptyString
Arb.register<Alt>()
let g = Arb.generate<MyUnion>
Gen.sample 1 10 g
Note that you'd need to re-register the default generator after the test since the mappings are global.
A more by-the-book solution would be to use the default derived generator and then filter values that contain invalid strings (i.e. use ==>), but you might find it not feasible for particularly deep nested types.

Linq to entities if in select statement

I have this linq query
Dim chiamateAperte = From statoRic In
dbVulcano.StatoRic.Where(Function(s) s.RFStato >= 11 And s.RFStato <= 13 And s.Attuale = 1 And s.RFTecnico = rfTecnico)
From richiesta In
dbVulcano.Richieste.Where(Function(r) r.IDRic = statoRic.RFRic).DefaultIfEmpty()
From cliente In
dbVulcano.Clienti.Where(Function(c) c.IDCliente = richiesta.RFCliente).DefaultIfEmpty()
Select statoRic.ID, statoRic.RFRic, statoRic.RFStato, statoRic.Attuale, richiesta.Descr, cliente.RagSociale, statoRic.DataAss, statoRic.Data, dataf = If(statoRic.DataAss.HasValue, statoRic.DataAss, statoRic.Data), statoRic.OraDalle, statoRic.OraAlle
Order By dataf Descending, statoRic.OraDalle Ascending
It's working fine but I want to add an order condition on "OraDalle" field.
OraDalle it's sort of a time field, but sadly on db it's defined as smallInt (and I cannot change it), so the format is like "800" to say "eight o'clock". This field can be null.
So instead of statoRic.OraDalle I tried this:
orad=if (statoRic.OraDalle.HasValue,statoRic.OraDalle,2359)
And then
Order By dataf Descending, orad Ascending
But it throws an ugly error: cannot cast system nullable 1 to system object of type 'system.nullable'. Only primitive types or enumeration types are supported in this context
Then I tried this:
orad=statoRic.OraDalle.GetValueOrDefault(2359)
But it also throw an error like: linq to entities does not recognize the method 'Int16 GetValueOrDefault(Int16)'
So... how can I achieve what I want? This whole mess is to get a list ordered by time, where null time values are at the bottom (and not on the top, as default). Thank you all!
Instead of if (statoRic.OraDalle.HasValue,statoRic.OraDalle,2359) use if (statoRic.OraDalle,2359)
This is the equivalent of C#´s null-coalescing-operator ??:
statoRic.OraDalle ?? 2359 which was the solution for a similar question.

How can I use the COUNT value obtained from a call to mkqlite()?

I'm using mksqlite to create and access an SQL database from matlab, and I want to get the number of rows in a table. I've tried this:
num = mksqlite('SELECT COUNT(*) FROM myTable');
, but the returned value isn't very helpful. If I put a breakpoint in my script and examine the variable, I find that it's a struct with a single field, called 'COUNT(_)', which seems to actually be an invalid name for a field, so I can't access it:
K>> class(num)
ans =
struct
K>> num
num =
COUNT(_): 0
K>> num.COUNT(_)
??? num.COUNT(_)
|
Error: The input character is not valid in MATLAB statements or expressions.
K>> num.COUNT()
??? Reference to non-existent field 'COUNT'.
K>> num.COUNT
??? Reference to non-existent field 'COUNT'.
Even the MATLAB IDE can't access it. If I try to double click the field in the variable editor, this gets spat out:
??? openvar('num.COUNT(_)', num.COUNT(_));
|
Error: The input character is not valid in MATLAB statements or expressions.
So how can I access this field?
You are correct that the problem is that mksqlite somehow manages to create an invalid field name that can't be read. The simplest solution is to add an AS clause to your SQL so that the field has a sensible name:
>> num = mksqlite('SELECT COUNT(*) AS cnt FROM myTable')
num =
cnt: 0
Then to remove the extra layer of indirection you can do:
>> num = num.cnt;
>> num
num =
0

NHibernate Like with integer

I have a NHibernate search function where I receive integers and want to return results where at least the beginning coincides with the integers, e.g.
received integer: 729
returns: 729445, 7291 etc.
The database column is of type int, as is the property "Id" of Foo.
But
int id = 729;
var criteria = session.CreateCriteria(typeof(Foo))
criteria.Add(NHibernate.Criterion.Expression.InsensitiveLike("Id", id.ToString() + "%"));
return criteria.List<Foo>();
does result in an error (Could not convert parameter string to int32). Is there something wrong in the code, a work around, or other solution?
How about this:
int id = 729;
var criteria = session.CreateCriteria(typeof(Foo))
criteria.Add(Expression.Like(Projections.Cast(NHibernateUtil.String, Projections.Property("Id")), id.ToString(), MatchMode.Anywhere));
return criteria.List<Foo>();
Have you tried something like this:
int id = 729;
var criteria = session.CreateCriteria(typeof(Foo))
criteria.Add(NHibernate.Criterion.Expression.Like(Projections.SqlFunction("to_char", NHibernate.NHibernateUtil.String, Projections.Property("Id")), id.ToString() + "%"));
return criteria.List<Foo>();
The idea is convert the column before using a to_char function. Some databases do this automatically.
AFAIK, you'll need to store your integer as a string in the database if you want to use the built in NHibernate functionality for this (I would recommend this approach even without NHibernate - the minute you start doing 'like' searches you are dealing with a string, not a number - think US Zip Codes, etc...).
You could also do it mathematically in a database-specific function (or convert to a string as described in Thiago Azevedo's answer), but I imagine these options would be significantly slower, and also have potential to tie you to a specific database.