Using the InfluxDB Java client to communicate w/ my InfluxDB instance from a Java app.
I'm trying to accomplish something that doesn't appear to be documented anywhere inside the project. For a particular measurement, I need to list its latest (timestamp-wise) field key(s) and their values without knowing what they are called!
Hence let's say I have a measurement called FizzBuzz:
> SHOW measurements
name: measurements
name
----
FizzBuzz
I believe ORDER BY ASC is InfluxDb's default meaning the last/latest measurement data is always the last to come back in the query by default. So I think I'm looking to run something like this from Java:
SELECT * FROM FizzBuzz ORDER BY DESC LIMIT 1;
However my app will not know what the field key(s) on that returned result will be, and so I need a way (via the API) to inspect the record that is return and obtain the name of any field keys (so I can save them as strings) and obtain their respective values (which I can safely assume can be cast to BigDecimals).
My best attempt thus far:
Query query = new Query("SELECT * FROM FizzBuzz ORDER BY DESC LIMIT 1", "my-app-db");
QueryResult queryResult = connection.query(query);
for(Result result : queryResult.getResults()) {
for(Series series : result.getSeries()) {
List<String> cols = series.getColumns();
// But how to tell whats a field vs whats a tag?!
}
}
However this doesn't allow me to discern which columns are fields vs. which ones are just tags...any ideas?
Related
I am creating an agent based model in Anylogic 8.7. There is a point that I want to use query to get a List of values from a database table(rs_table) with a condition, here is the Java code that anylogic writes at the designated place:
(int) selectFrom(rs_table) .where(rs_table.tr.eq(1)) .list(rs_table.impact)
but I do not know how to store those values and how to reach them one by one. I would be grateful if you help me out thanks.
I would use a collection. Add a collection element from the "Agent" Pallet. The collection should have the following properties:
Collection Class: LinkedList
Element Class: Int
Use the following code:
collection.addAll(
selectFrom(rs_table) .where(rs_table.tr.eq(1)) .list(rs_table.impact)
);
Now, you can access the value from the collection as follows:
collection.get(i);
The "Iterate over returned rows and do something" option of the Insert Database Query wizard is precisely designed for this. It produces query code that loops through the returned list and prints each column's value to the console (via a traceln call); you just replace the code within the loop with what you actually want to do for each returned row (where the template code shows you how to get the value of each column in the row).
The wizard (if you use the QueryDSL form) will produce code like below:
List<Tuple> rows = selectFrom(rs_table)
.where(rs_table.tr.eq(1))
.list();
for (Tuple row : rows) {
traceln(
row.get( rs_table.tr ) + "\t" +
row.get( rs_table.impact )
);
}
(with extra row.get lines for any other table columns beyond the tr and impact ones).
(In Java terms, the query's list function returns a List of Tuple objects as the code shows.)
I want to filter results by a specific value in the aggregated array in the query.
Here is a little description of the problem.
Section belongs to the garden. Garden belongs to District and District belongs to the province.
Users have multiple sections. Those sections belong to their gardens and they are to their Districts and them to Province.
I want to get user ids that have value 2 in district array.
I tried to use any operator but it doesn't work properly. (syntax error)
Any help would be appreciated.
ps: This is possible writing using plain SQL
rs = dslContext.select(
field("user_id"),
field("gardens_array"),
field("province_array"),
field("district_array"))
.from(table(select(
arrayAggDistinct(field("garden")).as("gardens_array"),
arrayAggDistinct(field("province")).as("province_array"),
arrayAggDistinct(field("distict")).as("district_array"))
.from(table("lst.user"))
.leftJoin(table(select(
field("section.user_id").as("user_id"),
field("garden.garden").as("garden"),
field("garden.province").as("province"),
field("garden.distict").as("distict"))
.from(table("lst.section"))
.leftJoin("lst.garden")
.on(field("section.garden").eq(field("garden.garden")))
.leftJoin("lst.district")
.on(field("district.district").eq(field("garden.district")))).as("lo"))
.on(field("user.user_id").eq(field("lo.user_id")))
.groupBy(field("user.user_id"))).as("joined_table"))
.where(val(2).equal(DSL.any("district_array"))
.fetch()
.intoResultSet();
Your code is calling DSL.any(T...), which corresponds to the expression any(?) in PostgreSQL, where the bind value is a String[] in your case. But you don't want "district_array" to be a bind value, you want it to be a column reference. So, either, you assign your arrayAggDistinct() expression to a local variable and reuse that, or you re-use your field("district_array") expression or replicate it:
val(2).equal(DSL.any(field("district_array", Integer[].class)))
Notice that it's usually a good idea to be explicit about data types (e.g. Integer[].class) when working with the plain SQL templating API, or even better, use the code generator.
I'm using
jdbcTemplate to make JDBC connections to a mySQL DB
prepared statements to protect myself as much as possible from SQL injection attacks
in need to accept requests from the user to sort the data on any of a dozen different columns
the following statement
jdbcTemplate.query("SELECT * FROM TABLE1 ORDER BY ? ?", colName, sortOrder);
Of course this doesn't work, because the variable bindings aren't supposed to specify column names just parameter values for expressions in the query.
So...how are people solving this issue? Just doing the sort in Java code seems like an easy solution, but since I'm getting a variable string for the column to sort on, and a variable telling me the sort order....that's an ugly number of comparator-conditions to cover. This seems like it should be a common problem with a common pattern to solve it...
Placeholders ? can only be used for parameter values but not with column and sort order directions. So the standard way to do this as is pointed e.g. here is to use String#format() or something similar to append your column name and order value to your query.
Another option is to use Spring Data JPA where you can give to your method as an argument an instance of type Sort which can contain all needed info for database to sort.
I would just concatenate the column name and the order to the SQL query, but only after
verifying that the column name and order are valid in this context.
sanitizing them to counter any attempt of SQL Injection attack.
I feel this is efficient compared to fetching the results to the application layer and sorting them here.
My suggestion is the mapping of keys and columns. It's a safe solution.
At the beginning, we initiate our map in the simplest possible way. For convenience, I overloaded the get (Obiect key) method to return the default column ("fullName") in case of failure. This will protect against SqlExeption.
static Map<String,String> sortCol;
{
sortCol = new HashMap<String, String>(){
{//Enter all data for mapping
put("name","fullName");
put("rok","year");
put("rate","likes");
put("count-rate","countRate");
}
/**
*
* #param key for column name
* #return column name otherwise default "fullName"
*/
#Override
public String get(Object key) {
String col =super.get(key);
return null==col?"fullName":col;
}
};
}
Here is a simple example of use.
String sqlQuery= "Select \"fullName\",year,likes,count-rate, country ..."+
"from blaBla..."+
"where blaBla..."+
"order by "+sortCol.get("keySort") "\n"; // keySort can have the value name, count-rate etc ..
By the way, you should never reveal the real names of columns in user interfaces, such as REST or SOAP etc ... For the attacker, this is a great help.
In unit tests I verify the result from a Db query that contains an "ORDER BY DESC" part and return String values.
To be clear: I check that the query returns the expected result in the expected order
SQL query:
SELECT member.name FROM member ORDER BY member.name DESC
Test result:
MTH_TESTER_TAXER_W_HLPERS_AFcCmhecUo
MTH_TESTER_TAXER_wCfRUAQuzT
When verifying the result with java, I do:
foreach(String value : values) {
if (previous != null) {
assertTrue(value.compareToIgnoreCase(previous) <= 0);
}
previous = value;
}
Which fails using the above DB result from the ORDER BY (descending order in above example).
So basically the following in java fails but not in DB:
assertTrue("MTH_TESTER_TAXER_wCfRUAQuzT".compareToIgnoreCase("MTH_TESTER_TAXER_W_HLPERS_AFcCmhecUo") <= 0)
Why is the ORDER BY not compatible with the Java compareTo natural String ordering?
And how to make them compatible?
I use Postgresql 9.X on Windowsd 7, default installation.
Try using string's CASE_INSENSITIVE_ORDER:
String[] str = {"abc", "pqr", "zxt", "Zxy", "xyz"};
Arrays.sort(str, String.CASE_INSENSITIVE_ORDER.reversed());
System.out.println(Arrays.toString(str));
If you change your sql to
SELECT member.name FROM member ORDER BY UPPER(member.name) DESC
your Java code will likely verify this order.
Alternatively, if you change your Java code to
foreach(String value : values) {
if (previous != null) {
assertTrue(value.compareTo(previous) <= 0);
}
previous = value;
}
it should verify the case-sensitive order being done by your current sql.
Are you trying to verify that your database query works correctly? If so, then i would first ensure I know exactly what is coming back from the database. There's no information in your code, but I would hope you're seeding the data before the test runs either through direct SQL or something like dbUnit.
Once you have this then you can do an exact comparison on the returned results in the test. I would avoid the test you currently have as it gives you no diagnostics about what is wrong when the test fails. When you have this in place your test can be something like:
List<String> expected = Arrays.asList("MTH_TESTER_TAXER_W_HLPERS_AFcCmhecUo", "MTH_TESTER_TAXER_wCfRUAQuzT");
List<String> actual = myCode.performQuery(); // <-- your method under test goes here
assertThat(expected, contains(actual));
This will ensure the collection you return has the same items in the same order as you specify and if something differs it will tell you exactly what.
There are two possible solutions here:
You don't rely on ORDER BY at all. You can use it but before you compare, you sort the actual output again in Java to make sure the order is always the same.
Use this approach if you only need to make sure that the actual sort order of the query doesn't really matter, only the number and content of the elements.
Instead of comparing each string individually, join the results into one multi-line string and then do a single assertEquals() with a constant string.
The second solution looks like this:
String actual = Joiner.on('\n').join(Ordering.natural().sortedCopy(values));
assertEquals(
"MTH_TESTER_TAXER_W_HLPERS_AFcCmhecUo\n" +
"MTH_TESTER_TAXER_wCfRUAQuzT",
actual
);
The second test checks all values at once, allowing you to see with a single glance which values have changed, which are unexpected and which are missing.
It also allows you to safely test the ordering of results as returned by the database.
I don't know if this is a problem that is specific to Google App Engine for Java, but if the value set as the keywords parameter is a null String, then nothing is returned from the query, even if a minPrice is set.
How do I change this query to make it return records that meet the minPrice condition even if the keywords value is null? Ideally I would somehow use the same query for both conditions without creating separate queries based on a null String condition.
Query qry = entityManager.createQuery("SELECT p FROM Test p
WHERE keywords = :keywords and price >= :minPrice");
qry.setParameter("keywords", keywords);
qry.setParameter("minPrice", Integer.parseInt(minPrice));
It's the way the GAE datastore works (most relational databases work that way too, btw!): nulls are not equal to anything, so the keywords = :keywords part of your query is false on records with null keywords -- since that part is false, so is the and, of course.
You'll need two queries, one for keywords = :keywords and one for the "is null" check, and use their two disjoint result sets (Python GAE simulates an "IN" operator in app-level code, which I believe Java GAE doesn't, but since the sets are disjoint in this case there's really no mystery or difficulty to it anyway;-).
Edit: it's a simulated IN (which would be usable here) in Python, not OR; the Java equivalent of that app-level-simulated IN is actually contains.