Postgresql PQgetvalue: array return - c

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.

Related

SQL Server: STRING_SPLIT() result in a computed column

I couldn't find good documentation on this, but I have a table that has a long string as one of it's columns. Here's some example data of what it looks like:
Hello:Goodbye:Apple:Orange
Example:Seagull:Cake:Chocolate
I would like to create a new computed column using the STRING_SPLIT() function to return the third value in the string table.
Result #1: "Apple"
Result #2: "Cake"
What is the proper syntax to achieve this?
At this time your answer is not possible.
The output rows might be in any order. The order is not guaranteed to
match the order of the substrings in the input string.
STRING_SPLIT reference
There is no way to guarantee which item was the third item in the list using string_split and the order may change without warning.
If you're willing to build your own, I'd recommend reading up on the work done by
Brent Ozar and Jeff Moden.
You shouldn't be storing data like that in the first place. This points to a potentially serious database design problem. BUT you could convert this string into JSON by replacing : with ",", surround it with [" and "] and retrieve the third array element , eg :
declare #value nvarchar(200)='Example:Seagull:Cake:Chocolate'
select json_value('["' + replace(#value,':','","' )+ '"]','$[2]')
The string manipulations convert the string value to :
["Example","Seagull","Cake","Chocolate"]
After that, JSON_VALUE parses the JSON string and retrieves the 3rd item in the array using a JSON PATH expression.
Needless to say, this will be slow and can't take advantage of indexing. If those values are meant to be read or written individually, they should be stored in separate columns. They'll probably take less space than one long string.
If you have a lot of optional fields but only a subset contain values at any time, you could use sparse columns. This way you could have thousands of rows, only a few of which would contain data at any time

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)

How to compare numeric in PostgreSQL JSONB

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.

How to take apart information between hyphens in SQL Server

How would I take apart a column that contains string:
92873-987dsfkj80-2002-04-11
20392-208kj48384-2008-01-04
Data would look like this:
Filename Yes/No Key
Abidabo Yes 92873-987dsfkj80-2002-04-11
Bibiboo No 20392-208kj48384-2008-01-04
Want it to look like this:
Filename Yes/No Key
Abidabo Yes 92873-987dsfkj80-20020411
Bibiboo No 20392-208kj48384-20080104
whereby I would like to concat the dates in the end as 20020411 and 20080104. From the right side, the information is the same always. From the left it is not, otherwise I could have concatenated it. It is not an import issue.
As mentioned in the comments already, storing data like this is a bad idea. However, you can obtain the dates from those strings by using a RIGHT function like so:
SELECT RIGHT('20392-208kj48384-2008-01-04', 10)
Output:
2008-01-04
Depending on the SQLSERVER version you are using, you can use STRING_SPLIT which requieres COMPATIBILITY_LEVEL 130. You can also build your own User Defined Function to split the contents of a field and manipulate it as you need, you can find some useful examples of SPLIT functions in this thread:
Split function equivalent in T-SQL?
Assuming I'm correct and the date part is always on the right side of the string, you can simply use RIGHT and CAST to get the date (assuming, again, that the date is represented as yyyy-mm-dd):
SELECT CAST(RIGHT(YourColumn, 10) As Date)
FROM YourTable
However, Panagiotis is correct in his comment - You shouldn't store data like that. Each column in the database should hold only a single point of data, be it string, number or date.
Update following your comment and the updated question:
SELECT LEFT(YourColumn, LEN(YourColumn) - 10) + REPLACE(RIGHT(YourColumn, 10), '-', '')
FROM YourTable
will return the desired results.

sqlite why select like works and equals does not?

I have a problem with sqlite3 database, I execute the following queries
sqlite> select * from property where link like
"http://www.domain.com/huur/den-bosch/appartement-48118689-meester-spoermekerlaan-88/";
I get two rows
17|2014-11-03|Meester Spoermekerlaan
88|http://www.domain.com/huur/den-bosch/appartement-48118689-meester-spoermekerlaan-88/|5237
JZ|Den Bosch|€ 789|3|1
32|2014-11-03|Meester Spoermekerlaan
88|http://www.domain.com/huur/den-bosch/appartement-48118689-meester-spoermekerlaan-88/|5237
JZ|Den Bosch|€ 789|3|1
Then I execute the same query, but using the equality operator, like so
sqlite> select * from property where
link="http://www.domain.com/huur/den-bosch/appartement-48118689-meester-spoermekerlaan-88/";
sqlite> (<---- no results??)
I already found a similar answer to mine, however the issue is not the same, my fields are of datatype "text", as you can see here: https://stackoverflow.com/a/14823565/279147
sqlite> .schema property
CREATE TABLE property (id integer PRIMARY KEY AUTOINCREMENT UNIQUE,"date" text,address text,link text,postcode text,city text,price text,rooms text,page integer);
So does anybody have any idea why this would happen? here is my version information
root#s1:/# sqlite3 application.sqlite3
SQLite version 3.7.3
I had the same problem. This work around worked for me.
SELECT * from foo WHERE CAST(name AS BLOB) = CAST('bla' AS BLOB);
SQLite uses dynamic typing; it does not matter if the link column is declared as text or blob or fluffy bunnies.
LIKE automatically converts its parameters into strings, but the = operator does not.
Fix the program that writes the entries to the database to use the correct data type.
I had similar issue, in my case the point was, the like is not case sensitive, but the = operator is case sensitive.
This is because = is a literal string comparison so it would have to be exactly the same.
The like operator is looking for a matching pattern within the string and finds it.

Resources