I have a column (Type TEXT) in my database where I store dynamic checklist items, stored in the following format: [{"checked":"true","nome":"CNH Colorida"},{"checked":"false","nome":"Contrato social"},{"checked":"false","nome":"Última fatura de energia"}]. I need to get which of them are checked, and which are not, using SQL. I used to have a PHP code that json_decode the string and then iterates it, but I want to be able to do this directly from the SQL. The PostgreSQL version is 9.4.
When I try to cast the returned row as json (select valor::json), nothing happens, and if I try to cast it to a json array (select valor::json[]), I get the following error:
SQL Error [22P02]: ERROR: malformed array literal: "[]"
Details: "[" must introduce explicitly-specified array dimensions.
By researches, I found that PostgreSQL arrays are defined with {}, and not []. If I translate the [] to {}, I get this error:
SQL Error [22P02]: ERROR: malformed array literal: "{{"checked":true,"nome":"Importado"},{"checked":false,"nome":"Finame"},{"checked":false,"nome":"MDA"}}"
Details: Unexpected array element.
What else can I try to get it working?
Once you have converted the text to json you need to unnest the array and extract the key values:
select d.v ->> 'nome' as name
from the_table t, json_array_elements(t.valor::json) as d(v)
where d.v ->> 'checked' = 'true';
Online example: https://rextester.com/TSRF14508
Related
I would like to use the value selected in a filter as a returned column.
For instance like
SELECT :MyFilter;
but I get the following error:
No valid expression found for :Subscription. Expecting "<expression> = :MyFilter" (line 1)
You may need to declare a local variable, assign it the value from :MyFilter, and then use in your query. See the following reference: https://docs.snowflake.com/en/developer-guide/snowflake-scripting/variables.html#working-with-variables
I read through snowflake documentation and the web and found only one solution to my problem by https://stackoverflow.com/users/12756381/greg-pavlik which can be found here Snowflake JSON to tabular
This doesn't work on data with Russian attribute names and attribute values. What modifications can be made for this to fit my case?
Here is an example:
create or replace table target_json_table(
v variant
);
INSERT INTO target_json_table SELECT parse_json('{
"at": {
"cf": "NV"
},
"pd": {
"мо": "мо",
"ä": "ä",
"retailerName": "retailer",
"productName":"product"
}
}');
call create_view_over_json('target_json_table', 'V', 'MY_VIEW');
ERROR: Encountered an error while creating the view. SQL compilation error: syntax error line 7 at position 7 unexpected 'ä:'. syntax error line 8 at position 7 unexpected 'мо'.
There was a bug in the original SQL used as a basis for the creation of the stored procedure. I have corrected that. You can get an update on the Github page. The changed section is here:
sql =
`
SELECT DISTINCT '"' || array_to_string(split(f.path, '.'), '"."') || '"' AS path_nAme, -- This generates paths with levels enclosed by double quotes (ex: "path"."to"."element"). It also strips any bracket-enclosed array element references (like "[0]")
DECODE (substr(typeof(f.value),1,1),'A','ARRAY','B','BOOLEAN','I','FLOAT','D','FLOAT','STRING') AS attribute_type, -- This generates column datatypes of ARRAY, BOOLEAN, FLOAT, and STRING only
'"' || array_to_string(split(f.path, '.'), '.') || '"' AS alias_name -- This generates column aliases based on the path
FROM
#~TABLE_NAME~#,
LATERAL FLATTEN(#~COL_NAME~#, RECURSIVE=>true) f
WHERE TYPEOF(f.value) != 'OBJECT'
AND NOT contains(f.path, '[') -- This prevents traversal down into arrays
limit ${ROW_SAMPLE_SIZE}
`;
Previously this SQL simply replaced non-ASCII characters with underscores. The updated SQL will wrap key names in double quotes to create non-ASCII key names.
Be sure that's what you want it to do. Also, the keys are nested. I decided that the best way to handle that is to create column names in the view with dot notation, for example one column name is pd.ä. That will require wrapping the column name with double quotes, such as:
select * from MY_VIEW where "pd.ä" = 'ä';
Final note: The name of your stored procedure is create_view_over_json, however, in the Github project the name is create_view_over_variant. When you update, be sure to call the right procedure.
I'm using SQL SERVER 2016 JSON result, but I don't know why it converts everything to array, e.g. if I execute the following query it returns an array instead of an object:
SELECT 1 AS One,2 AS Two,3 AS Three
FOR JSON PATH
The result is:
[{"One":1,"Two":2,"Three":3}]
But I would like it to return:
{"One":1,"Two":2,"Three":3}
Also I tested this query, but the result was the same, again an array:
SELECT TOP 1 1 AS One,2 AS Two,3 AS Three
FOR JSON PATH
You just need the WITHOUT_ARRAY_WRAPPER option:
SELECT 1 AS One,2 AS Two,3 AS Three
FOR JSON PATH ,WITHOUT_ARRAY_WRAPPER;
I'm currently working on a function in PostgreSQL, where it takes in an array of integers. Everything in the function is working as expected, however at one point in the function I do the following:
EXECUTE
'INSERT INTO tmptable (user_id)
SELECT DISTINCT user_id FROM user_skills
WHERE skill_values_id=ANY('||selected_skills||')';
My function is able to read the array at other points in the code, however this part throws the following error:
Procedure execution failed
ERROR: malformed array literal: "
INSERT INTO tmptable (user_id)
SELECT DISTINCT user_id FROM user_skills
WHERE skill_values_id=ANY("
And finally- there is a line at the bottom of the error message that says:
DETAIL: Array value must start with "{" or dimension information.
Any ideas how to get the any and integer array to play nice? I'm assuming it has something to do with the || concentration casting it to a string?
Don't concatenate values, use parameters instead:
EXECUTE
'INSERT INTO tmptable (user_id)
SELECT DISTINCT user_id FROM user_skills
WHERE skill_values_id=ANY($1)'
using selected_skills;
More details in the manual:
https://www.postgresql.org/docs/current/static/plpgsql-statements.html#PLPGSQL-STATEMENTS-EXECUTING-DYN
There is a table in postgres DB test1 having schema :
We are using spring frameworks jdbcTemplate to insert data as below:
Object[] params = {"978","tour"};
jdbcTemplate.update("insert into test1 values (?,?)", params);
But this gives the exception :
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [insert into test1 values (?,?)]; nested exception is org.postgresql.util.PSQLException: ERROR: column "id" is of type integer but expression is of type character varying
ERROR: column "id" is of type integer but expression is of type character varying
This works for Oracle database through implicit type conversion, but postgres does nOt seem to work that way.
Could this be an issue with postgres driver?
A workaround would be to cast explicitly:
insert into test1 values (?::numeric ,?)
But is there better way to do the conversion as this does not seem like a good solution since there are lot of queries to be modified and also there can be other such casting issues too.
Is there some parameter that can be set at DB level to perform an auto cast?
We found the answer here
Storing json, jsonb, hstore, xml, enum, ipaddr, etc fails with "column "x" is of type json but expression is of type character varying"
A new connection propertyshould be added :
String url = "jdbc:postgresql://localhost/test";
Properties props = new Properties();
props.setProperty("user","fred");
props.setProperty("password","secret");
props.setProperty("stringtype", "unspecified");
Connection conn = DriverManager.getConnection(url, props);
https://jdbc.postgresql.org/documentation/94/connect.html
"If stringtype is set to unspecified, parameters will be sent to the server as untyped values, and the server will attempt to infer an appropriate type. This is useful if you have an existing application that uses setString() to set parameters that are actually some other type, such as integers, and you are unable to change the application to use an appropriate method such as setInt()"
Yeah, drop the double quotes here:
Object[] params = {"978","tour"};
Becomes
Object[] params = {978,"tour"};
Alternatively do the casting as you mentioned.