How to change number formatting for Hana SQL query session or connection? - hana

For our customers that use SAPB1 with HanaDB we execute the same query to pull data out (using the ADO.NET interface). Some have their regional system systems that appear to control numerical formatting according to their locale, etc.
Say for example when executing: SELECT RDR1."Quantity" FROM RDR1
For a customer in the USA, RDR1."Quantity" = 2.000000
For a customer in Germany, RDR1."Quantity" = 2,000000 (notice the comma vs decimal)
I assume the actual database storage of the value is the same, it is just the query engine that is applying default system formatting based on the settings that makes the end result formatted one way or another.
Now, using a brute force approach and per column this type of change can be made:
REPLACE(CAST(ROUND(RDR1."Quantity",2) AS DECIMAL(10,2)), ',', '.') AS "Quantity”
to give me "2.00"
However we have many columns like this and we want to make the code usable in all cases vs having multiple instances of the same queries for different regions -- and it just seems there should be a way to tell the query engine to return values as if it were in the USA and ignore default system locale and currency settings.
Question: Is it possible to make a high level setting change instead of per column formatting/casting - either using Hana SQL query code (like a session variable or something) or a connection setting when we establish the ADO.NET connection to HanaDB that will just make the values come out as if they were in the USA?
I haven't found any yet but perhaps it is not so easily found in the documentation how to handle it.

No, there is no HANA setting that would define how the application, SAP Business One in your case, renders the data to the user screen.
For SAP B1 you can find the documentation for setting these user settings here.
These settings include "thousands separator", "separator", "decimal places", and others.
But on HANA DB level, there is no global setting for that.
Also, the REPLACE workaround mentioned turns the input number data into a string, losing all the number semantics (ordering, mathematical operations) and increase the memory requirements for those values.
Rather avoid this technique if possible.

If you want to alter the decimal separator of the program output, just tell it to .NET.
An option is to set the Current Thread's Culture like in this snippet:
using System;
using System.Globalization;
class Program
{
static void Main(string[] args)
{
decimal d = 2021.1002m;
Console.WriteLine("Current Culture is {0}.", System.Threading.Thread.CurrentThread.CurrentCulture.Name);
Console.WriteLine("d = {0}.", d);
System.Threading.Thread.CurrentThread.CurrentCulture =
new CultureInfo("en-US");
Console.WriteLine("Current Culture now is {0}.", System.Threading.Thread.CurrentThread.CurrentCulture.Name);
Console.WriteLine("And d = {0}.", d);
}
}
For me the ouput is:
Current Culture is es-ES.
d = 2021,1002.
Current Culture now is en-US.
And d = 2021.1002.

Related

How to define a general property for the entire database

I'm managing a database with sqlite and I want to hold a general property
describing the version of my application. This property will be updated for every database change. Is it possible?
If all you want to do is track an application version, Sqlite has a couple of pragmas for querying and setting integer values that are part of the database file format itself, intended for just such a thing.
APPLICATION_ID: This one is meant to be assigned an application-specific ID number that you can check to make sure the database is one created by your program and not something else.
USER_VERSION: This is probably what you'll want to use. I use it for the same purpose you're describing, incrementing it with every new table or whatever, so that if a database with an older schema version is loaded into a program that uses a newer one, it can then upgrade the database as appropriate.
Is it possible?
Yes and is frequently used.
Android's SQLiteOpenHelper class (which you can subclass to) checks the version passed against the version stored.
If the version passed is higher than the version stored then the method (abstract so has to be overridden) onUpgrade is called.
If the version is lower then the onDowngrade method (not abstract but if not overridden results in an exception).
The value is stored in the user_version (offset 60-63 inclusive, in the database header, the first part of the database file) and is a 32bit signed integer.
It can be read by issuing PRAGMA user_versionand then extracted from the result set as column user_version.
It can be set by issuing PRAGMA user_version = ? (where ? is the number that you want it set to).
The highest value that it can be set to is 2147483647, the lowest is -2147483648 values outside of this range result in 0.
PRAGMA user_version;
As an example :-
PRAGMA user_version = -2147483648;
PRAGMA user_version;
PRAGMA user_version = 2147483647;
PRAGMA user_version;
will result in the two requests to return the user_version (2nd an 4th lines) as per :-
and
The next 4 bytes in the header the application_id could be used in a similar way. It's intended to describe a file type akin to file extension like .doc, .pdf and so on and used when Sqlite is used as an application file format. This value being interrogated by the application which then acts accordingly reading storing and retrieving the data.
It's probably not a frequently used value so could also be used in the same way just with different PRAGMA's. PRAGMA application_id and PRAGMA application_id = ? (again where ? is a 32bit signed integer)
PRAGMA application_id;
SQLite As An Application File Format
SQLite As An Application File Format - Benefits(short version)
Database File Format - The Database Header

MS Project equivalent to "xlAnd". Enumeration for logical operators

I'm trying to write a language independent filter for MS Project in VBA. I'm using the syntax:
FilterEdit (Name, Taskfilter, Create, Fieldname, Test, Value, Operation...)
I have managed to get the Fieldnames and Tests to be language independent, but I struggle with the Operation:= expression. For an English locale one would write: Operation:="and" but that doesnt work for other locales.
Is there a way to write the logical operator (and/or) as an enumeration? (not as a string?)
For Excel one could write xlAnd, and Project has a lot of enumerations starting with Pj, ie. PjTaskStart. I also know there's a Filter.LogicalOperationType, but I haven't managed to figure out if this could work for me or not. I have also experimented with FieldConstantToFieldName, but I reckon there's no fieldname for the logical operator?
I know I could use If LocaleID = xxxx Then..., but I'd like to not assume what locales will be in use.
Edit: I solved the first part of my problem!
By leaving it blank Operation:="", Project returns "And". But I haven't figured out yet how to return "Or"...
Operation:="" works for FilterEdit, but not for SetAutoFilter.
So I ended up using the dreaded If LocaleID.
Teaching moment:
I found out most operators can be language independent, except for:
And, Or, Contains and Does Not Contain.
These needs to be translated for each locale. I'll get to those in a minute. First I'll list all the language independent operators:
< Less than <= Less than or equal to > Greater than >= Greater than or equal to = Equal to <> Not equal to
My trick for finding the translations I need for the language dependent operators is the following MS Office Support page.
Notice the category named "Filter for specific text" in the English support page. Here we can read all the "words" we need. Now go to the bottom of the web page and change the language:
This opens up a new page listing all the different languages (not locale specific). Remembering where you found the word for Contains in English, then changing the language to for instance "Magyar (Magyarorzág)", we can now see that Contains = "Tartalmazza" in Magyar.
Next step is to google "Magyar languge" and learn that this actually equals Hungarian. So now you can go to this MSDN web page to see that Hungarian = LocaleID: 1038.
Putting all this together inside VBA makes you have to write the following code:
Dim LocalContains As String
If LocaleID = 1038 Then
LocalContains = "Tartalmazza" 'Hungarian
ElseIf LocaleID = 1044 Then
LocalContains = "inneholder" 'Norwegian
Else
LocalContains = "contains" 'English
End If

AS400 RPGLE/free dynamic variables in operations

I'm fairly certain after years of searching that this is not possible, but I'll ask anyway.
The question is whether it's possible to use a dynamic variable in an operation when you don't know the field name. For example, I have a data structure that contains a few hundred fields. The operator selects one of those fields and the program needs to know what data resides in the field from the data structure passed. So we'll say that there are 100 fields, and field50 is what the operator chose to operate on. The program would be passed in the field name (i.e. field50) in the FLDNAM variable. The program would read something like this the normal way:
/free
if field50 = 'XXX'
// do something
endif;
/end-free
The problem is that I would have to code this 100 times for every operation. For example:
/free
if fldnam = 'field1';
// do something
elseif fldnam = 'field2';
// do something
..
elseif fldnam = 'field50';
// do something
endif;
Is there any possible way of performing an operation on a field not yet known? (i.e. IF FLDNAM(pointer data) = 'XXX' then do something)
If the data structure is externally-described and you know what file it comes from, you could use the QUSLFLD API to find out the offset, length, and type of the field in the data structure, and then use substring to get the data and then use other calculations to get the value, depending on the data type.
Simple answer, no.
RPG's simply not designed for that. Few languages are.
You may want to look at scripting languages. Perl for instance, can evaluate on the fly. REXX, which comes installed on the IBM i, has an INTERPRET keyword.
REXX Reference manual

Formatting duration for display

In a SAP database there are values formatted as PxDTyH where x is the number of days and y is the number of hours. A value like P2DT0H is 2 days + 0 hours. I can see that via SE16:
Unfortunately, this is exactly displayed like that to the user, "3" corresponds to the index in the database (not seen in the screenshot above).
I'd like to see it displayed
without the index (changing the options "show keys within drop-down lists" did not have an effect)
instead of the technical name P2DT0H I'd like to see "2 days and 0 hours" (or similar)
Is there a way to process the data before it gets displayed in the combo box? The developers can't change the format in the database because it would change the API.
FYI: I'm just a tester, I don't know how to code in ABAP, but from knowledge of other programming languages, I'd say that the data can be converted before it's displayed. I don't need a fully-fledged answer, just a pointer to a SAP hook or event which enables writing a conversion function.
Probably, conversion routines can be an option for you. What you should do is to:
Take your domain (which is used for PxDTyH values) or create new one specially for this.
Create FM with name CONVERSION_EXIT_%NAME%_OUTPUT, and put conversion logic in there. Mandatory parameters INPUT and OUTPUT should exist.
Enter the %NAME% into Convers.routine field in domain properties.
Enable Check conversion exits checkbox in user parameters.
More info is here.

Auto incrementing w/ a vb.net chart control

I'm curious to know if the DataVisualization.charting.chart in vb.net does any auto counting / plotting for my particular issue.
I have a file with thousands of User Agent Strings which were generated over a period of time. The UA Strings are generated from user logins.
In my program, I am identifying approximately 45 different environments as: Operating Systems + Browser Type (ie., "Windows 7 + IE10"). Each login also has a date stamp in the format of YYYY-MM.
My task is to do a line chart where I have Environment (Y-axis) vs Date (X-axis) using the vb.net charting control. I would like the control to increment each time I have a particular data set rather than keeping a hideous amount of arrays & counter data for my chart.
Does the vb.net charting control auto increment in this way? I am not able to find anything so far.
I'm not sure I understand the question (what is it that you want to auto increment? The axis min/max? The date? Something else?), but if you want the axes to update each time you add a new point, the chart certainly supports that. Just call Chart.ResetAutoValues() after you add the new point(s), and it will figure out new ranges for both axes.
Edit: Arrange your data before adding it to the chart. Something like:
Dictionary<string, int> values = new ...;
string[] uaStrings = ReadFileOfUAStrings();
foreach (string uaString in uaStrings)
{
values[uaString]++;
}
foreach (KVP in values)
{
chart.Series(kvp.Key).Points.Add(kvp.Value);
}
The above doesn't separate things out by date, but you should get the idea. As written, it's also not very efficient if another UA string is added to the file and the whole thing is re-read, but optimizations can come after it's functional.