How to compare numeric in PostgreSQL JSONB - database

I ran into strange situation working with jsonb type.
Expected behavior
Using short jsonb structure:
{"price": 99.99}
I wrote query like this:
SELECT * FROM table t WHERE t.data->price > 90.90
And it fail with error operator does not exist: jsonb > numeric the same as text (->>) operator does not exist: text > numeric
Then I wrote comparison as mentioned in many resources:
SELECT * FROM table t WHERE (t.data->>price)::NUMERIC > 90.90
And it's works as expected.
What's strange:
SELECT * FROM table t WHERE t.data->price > '90.90';
a little weird but query above works right.
EXPLAIN: Filter: ((data -> 'price'::text) > '90.90'::jsonb)
But if I change jsonb value to text as: {"price": "99.99"}
there is no result any more - empty.
Question: How actually PostgreSQL compare numeric data and what preferable way to do this kind of comparison.

But you aren't comparing numeric data, are you.
I can see that you think price contains a number, but it doesn't. It contains a JSON value. That might be a number, or it might be text, or an array, or an object, or an object containing arrays of objects containing...
You might say "but the key is called 'price' of course it is a number" but that's no use to PostgreSQL, particularly if I come along and sneakily insert an object containing arrays of objects containing...1
So - if you want a number to compare to you need convert it to a number (t.data->>price)::NUMERIC or convert your target value to JSON and let PostgreSQL do a JSON-based comparison (which might do what you want, it might not - I don't know what the exact rules are for JSON).
1 And that's exactly the sort of thing I would do, even though it is Christmas. I'm a bad person.

Related

How can I parse JSON arrays in postgresql?

I am using PostgreSQL 9.5.14, and have a column in a table that contains JSON arrays that I need to parse for their contents.
Using a select I can see that the structure of the JSON is of this kind:
SELECT rule_results from table limit 5;
Result:
[{"rule_key":"applicant_not_lived_outside_eu"},{"rule_key":"family_assets_exceed_limit"},{"rule_key":"owned_a_deed"}]
[]
[]
[{"rule_key":"family_category","details":"apply_with_parents_under_25"}]
[]
I have been unable to create an SQL command to give me the values of the rule_key keys.
I've attempted to use the documentation for json-functions in postgresql to find a solution from
https://www.postgresql.org/docs/9.5/functions-json.html
SELECT rule_results::json->'rule_key' as results from table;
This gives me null values only.
SELECT jsonb_object_keys(rule_results::jsonb) from table;
This results in the error msg "cannot call jsonb_object_keys on a scalar", which seems to mean that the query is limited to a single row.
This looks simple enough, an array with key:value pairs, but somehow the answer eludes me. I would appreciate any help.
demo: db<>fiddle
Different solutions are possible. It depends on what you are expecting finally. But all solutions would use the function json_array_elements(). This expands every element into one row. With that you can do whatever you want.
This results in one row per value:
SELECT
value -> 'rule_key'
FROM
data,
json_array_elements(rule_results)

Find rows with exact geography coordinates

I have a SQL table with a geography column. When I look at one of the rows the geography shows as a long hex string: 0xE6100....C0.
I want to write a query that finds all other rows in my database that have this same value. How can I do this?
I tried adding WHERE location = '0xE6100....C0' with and without quotes but I get an error:
Invalid operator for data type. Operator equals equal to, type equals geography.
Note: I'm just doing this query in an ad-hoc fashion I'm not really looking for a optimal solution or a way to parameterize this in any way. I just have a row that I'd like to find related values.
Looks like you need to use .STEquals
Check the documentation here

T-SQL, Find numeric values

I did this quiz on http://www.sql-ex.ru/, question 35 to be exact.
The question is as follows:
In Product table, determine the models which consist only of digits or only of latin letters (A-Z, case insensitive).
Result set: model, type of model.
And I gave the correct answer which is:
SELECT model,
type
FROM Product
WHERE Model NOT LIKE '%[^A-Z]%'
OR Model NOT LIKE '%[^0-9]%'
Now my question is why do I need double negations to make it work.
If I rewrite the code to:
SELECT model,
type
FROM Product
WHERE Model LIKE '%[A-Z]%'
OR Model LIKE '%[0-9]%'
I get the wrong answer:
Your query returned the correct dataset on the first (available) database, but it returned incorrect dataset on the second checking database.
* Wrong number of records (more by 37)
How come that the first example of code gives the correct answer while the second example doesn´t?
I have tried to find answer but no luck. Grateful for an explanation.
Where Model LIKE '%[A-Z]%' Or Model LIKE '%[0-9]%'
Matches rows where Model contains at least one alpha numeric character.
This does not exclude in any way those values that contain mixed alphanumeric and non-alphanumeric characters.
e.g. ~A#- would pass because of the presence of the A
Moreover your correct query matches either
'%[^A-Z]%': those strings which do not contain any non letters (i.e. consist of only letters or are empty)
'%[^0-9]%': those strings which do not contain any non digits (i.e. consist of only digits or are empty).
This is not handled at all in your second attempt and a mixed string of letters and digits would be accepted by that.
I would use your first attempt but if you were determined to avoid the double negative you could use
SELECT model
FROM Product
WHERE Model LIKE REPLICATE('[A-Z]', LEN(Model))
OR Model LIKE REPLICATE('[0-9]', LEN(Model))

How to use NSPredicate with NSPredicateEditor on different data (Multiple Predicates?)

I've got an array of filepaths and I've got a NSPredicateEditor setup in my UI where the user can combine a NSPredicate to find a file. He should be able to filter by name, type, size and date.
There are several problems I have now:
I can only get one predicate object from the editor. When I use
"predicateForRow:" it returns (null)
If the user wants to filter the file by name AND size or date, I
can't just use this predicate on my array anymore because those
information are not contained in it
Can I split up a predicate into different predicates without
converting it into a NSString object, then search for every #" OR " |
#" AND " and seperating the components into an array and then
converting every NSString into a new predicate?
In the NSPredicateEditor settings I've some options for the "left Expression":
Keypaths, Constant Values, Strings, Integer Numbers, Floating Point Numbers and Dates. I want to display a dropdown menu to the user with "name", "type", "date", "size". But then the generated predicate automatically looks like this:
"name" MATCHES[c] "nameTest" OR "type" MATCHES[c] "jpg" OR size == 100
Because the array is filled with strings, a search for "name", "type" etc. and those strings do not respond to #"myString"*.name*m the filter always returns 0 objects. Is there a way to show the Name, Type, Size and Date in the Menu, but write "self" into the predicate without doing it by hand?
I've already searched in the official Apple tutorials, on Stackoverflow, Google, and even Youtube to find a clue. This problem troubles me for almost one week now. Thanks for you time! If you need more information please let me know!
You have come to the right place! :)
I can only get one predicate object from the editor.
Correct. It is an NSPredicateEditor, not an NSPredicatesEditor. ;)
When I use "predicateForRow:" it returns (null)
I'm not sure I would use that method. My general rule of thumb is to largely ignore that NSPredicateEditor is a subclass of NSRuleEditor, mainly because it's such a highly specialized subclass that many of the superclass methods don't make that much sense on a predicate editor (like all the stuff about criteria, row selection, etc). It's possible that they're somehow relevant, but if they are, I haven't figured out how yet.
To get the predicate from the editor, you do:
NSPredicate *predicate = [myPredicateEditor objectValue];
If the user wants to filter the file by name AND size or date
You mean (name = [something]) AND (size = [something] OR date = [something])?
If so, NSPredicateEditor can do that if you've set the nesting mode to "Compound".
I can't just use this predicate on my array anymore because those information are not contained in it
What information do you need?
Can I split up a predicate into different predicates without converting it into a NSString object, then search for every #" OR " | #" AND " and seperating the components into an array and then converting every NSString into a new predicate?
Yes, but that is a BAD idea. It's bad because NSPredicate already contains all the information you need, and converting it to a different format and doing string manipulations just isn't necessary and can potentially lead to complications (like if someone can type in a value for "name", what happens if they type in " OR "?).
I'm having a hard time trying to figure out what it is you're trying to do. It sounds like you have an array of NSString objects that you want to filter based on a predicate that the user creates? If so, then what do these name, date, and size key paths mean? What are you trying to do?

Postgresql PQgetvalue: array return

I've a table created like:
CREATE TABLE tbl_test
(
id bigserial PRIMARY KEY,
interest int ARRAY[2]
);
I got PGresult* res using PQexec(conn, "SELECT * FROM tbl_test");
Now, how can I get int[] from PQgetvalue(res, 0, 1).
I don't want to depend on structs defined in array.h as they might change.
I could not find any API in Postgresql docs which can do things.
Please advise.
Regards,
Mayank
PQgetvalue() returns the string representation of the field value unless you specify a binary cursor. In either case (string or binary cursor) you'll need to supply the code to manipulate the result into the form you want.
You might find some ideas in the PostgreSQL source code.
src/backend/utils/adt/arrayfuncs.c
src/include/utils/array.h.
And there's some code in contrib/intarray.
At http://doxygen.postgresql.org/, click "Files", then search for "array".
At the string level, which is what PQgetvalue() returns, it's probably easy to Google up some code that extracts integers from an comma-delimited string.

Resources