What could be the reason that some strings are not inserted into PostgreSQL table from Java?
This happens after an update of source of data from API v1 to API v2. The inserted data structure is almost the same, float values are inserted, but some strings are not. And without any error: the fields are just empty.
It is probably some escape character but I'm not able to figure out which one. And how to fix it as well. The string length is about 6k characters and its PostgreSQL representation is text.
Here is the stored procedure:
CREATE OR REPLACE FUNCTION add_data_string(in_ts bigint, in_ids integer[], in_string_values text[])
RETURNS integer AS
$BODY$
DECLARE
tmp_id integer;
tmp_index integer;
BEGIN
tmp_index := 0;
FOREACH tmp_id IN ARRAY in_ids LOOP
tmp_index := tmp_index +1;
INSERT INTO data (ts, id, string_value) VALUES (in_ts, tmp_id, in_string_values[tmp_index]);
END LOOP;
RETURN tmp_index;
END;
The strings are passed into the procedure like this:
cs.setArray(3, con.createArrayOf("varchar", (String[]) values));
There is one more thing: if the stored procedure is modified, for the sake of debug, that only first five characters of the string are inserted, e.g. like this:
INSERT INTO data (ts, id, string_value) VALUES (in_ts, tmp_id, substring(0, 5, in_string_values[tmp_index]));
the first five characters are inserted as expected.
Check the in_ids and in_string_values arrays before you pass them to PostgreSQL. My guess is that their sizes do not match (the string_values array probably has a few extra empty string values you do not expect) like this
ids string_values
1 "string that makes it to the database"
2 "" //unexpected empty string
"string which does not get inserted in the database"
The problem is in pgAdmin III which for some strange reason does show empty fields for strings longer than 3640 characters even though the value Max. characters per column is set to 4096.
Related
I have a requirement where I need to generate an account number and insert it into a table column in the following format.
"TBA2222011300000001" = where "TBA" is the value of another column or user sent data "22220113" implies the current date and "00000001" is a seven digit sequence that needs to be incremented and appended for every insert.
How can I append the sequence to the column, Should I do it in java or can it be done at DB end. I am currently using postgres with java and spring boot.
https://www.postgresql.org/docs/current/ddl-generated-columns.html
A generated column is a special column that is always computed from
other columns.
Several restrictions apply to the definition of
generated columns and tables involving generated columns:
The generation expression can only use immutable functions and cannot use subqueries or reference anything other than the current row
in any way.
now() is mutable function, so you cannot use Generated columns.
I am not sure why Default not working.
https://www.postgresql.org/docs/current/ddl-default.html
So now the only option is trigger.
CREATE TABLE account_info(
account_id INT GENERATED ALWAYS AS IDENTITY,
account_type text not null,
acconut_number text ) ;
So what you want is to automate:
UPDATE account_info set
account_number =
concat(
account_type,
to_char(CURRENT_DATE, 'yyyymmdd'),
to_char(account_id, 'FM00000000'));
create the function
create or replace function update_account_number() returns trigger as $$
BEGIN
UPDATE account_info set
account_number =
concat(
account_type,
to_char(CURRENT_DATE, 'yyyymmdd'),
to_char(account_id, 'FM00000000'));
RETURN NULL;
end;
$$ LANGUAGE plpgSQL;
create the trigger:
CREATE OR REPLACE TRIGGER udpate_accout_number
AFTER INSERT ON account_info
FOR EACH ROW
EXECUTE FUNCTION update_account_number();
Have an id column which is identity in postgres with start and end index as required.
For your reference to create identity column as desired
https://www.postgresqltutorial.com/postgresql-identity-column/
Have 1 more column for createdDate.
Then account number is simply a derived value TBA + formatted(DATE) + formatted(Id).
Ex -
No not a trigger just a function. There won't be any account number column in your table. It will simply be a function which takes date and identity as input and gives account number as output. Since account number is only dependent on id and date. No need to store this value at all, whenever you need the account number just call that function. Account number will not exist at all. It will always be calculated based on id and date. Simple.
Refer this in the article
Method 1: Derived Value called "markup"
The first method we may want to add to this table is a accountNumber method, for calculating our accountNumber based on current date and id. Since this value will always be based on two other stored values, there is no sense in storing it (other than possibly in a pre-calculated index). To do this, we:
CREATE FUNCTION accountNumber(id,date) RETURNS varchar AS
$$ SELECT TBA + format(id) + format(date)
$$ LANGUAGE SQL IMMUTABLE;
You need to put logic for format(id) and format(date) as per your requirement.
There is no point of storing the value which can be easily derived from other 2 columns. It would unnecessary consume space. Also maintaining data integrity and checks will be an overhead.
Creating function for derived values
https://ledgersmbdev.blogspot.com/2012/08/postgresql-or-modelling-part-2-intro-to.html
You can use the function in output as well as search.
Index would also be utilized as required.
I did the following to generate the desired account number.
Created a new sequence and appended zeros to it.
select to_char(nextval('finance_accounts_id_seq'), 'fm00000000')
Got the Current date in java using DateTimeFormatter
DateTimeFormatter dmf = DateTimeFormatter.ofPattern("yyyyMMdd");
String date = LocalDate.now().format(dmf);
Got the "TBA" from request param of the user.
I want to print 4 different values from my database table in 4 different Java Textfields when u click in the corresponding row.
You can use String.valueOf(arg) to convert to string your values. Also if the values coming from your database are numeric, you might want to call getDouble or getFloat on your ResultSet object too. Don't forget to remove the casts in the query as you will tranform the values in the Java code instead, like this:
textFieldEröffnungspreis.setText(String.valueOf(rs.getDouble("Eröffnungspreis")));
I am working with a program that i have a record for every user. My users have a property with key, PhoneNumber , and its value is an array of strings, [454457,897356]. For example if i wanted to use cypher query:
Start n=node(1)
Return n
It returns 1 record for my node(one row) that the value of column PhoneNumber is an array.
But i want to have record numbers according to the number of values in my array, means that for my example, the query returns 2 records(2 rows) and all of its attributes be the same but in the PhoneNumber column one of them has the value 454457 and the other has the value 897356. Is any way to do that? do i change my cypher query or make some changes in my java code?
Thanks.
There is no way to do that yet, within Cypher. I've submitted a request for it, though:
https://github.com/neo4j/neo4j/issues/30
I'm using a Spring jdbcTemplate.update(String sql, Object[] args) to execute a prepared insert statement on an Oracle database. One of the objects is a Character object containing the value 'Y', and the target column is of CHAR(1) type, but I'm receiving a
java.sql.SQLException: Invalid column type
exception.
I've debugged this backwards and forwards and there is no doubt that it is this one particular object that is causing the problem. The insert executes as expected when this Character Object is omitted.
I can also output the sql and Object[] values, copy the sql into sql developer, replace the value placeholders (?'s) with the actual values of the Objects, and the insert will work fine.
The sql (obfuscated to protect the guilty):
INSERT INTO SCHEMA.TABLE(NUMBER_COLUMN,VARCHAR_COLUMN,DATE_COLUMN,CHAR_COLUMN) VALUES (?,?,?,?);
The object values:
values[0] = [123]
values[1] = [Some String]
values[2] = [2012-04-19]
values[3] = [Y]
The combination run manually in sql developer and that works just fine:
INSERT INTO SCHEMA.TABLE(NUMBER_COLUMN,VARCHAR_COLUMN,DATE_COLUMN,CHAR_COLUMN) VALUES (123,'Some String','19-Apr-2012','Y');
The prepared statement sql itself is generated dynamically based on the non-null instance variable objects contained within a data transfer object (we want the database to handle generation of default values), so I can't accept any answers suggesting that I just rework the sql or insertion routine.
Anyone ever encountered this and can explain to me what's going on and how to fix it? It's frustratingly bizzare that I can't seem to insert a Character object into a CHAR(1) field. Any help would be much appreciated.
Sincerely, Longtime Lurker First-time Poster
There is no PreparedStatement.setXxx() that takes a character value, and the Oracle docs states that all JDBC character types map to Java Strings. Also, see http://docs.oracle.com/javase/1.3/docs/guide/jdbc/getstart/mapping.html#1039196, which does not include a mapping from Java char or Character to a JDBC type.
You will have to convert the value to a String.
Slightly broad question here, but here goes
I'm trying to call an Oracle stored procedure, which returns a VARRAY which is of constructed from a ROWTYPE on one of my tables. For simplicity, lets say this table looks like the following :
MY_TABLE
ID VALUE
-----------
1 John
2 Dave
so I will call a SP that returns the following VARRAY type :
CREATE OR REPLACE TYPE param_array is VARRAY(100) OF MY_TABLE%ROWTYPE;
According to the Oracle Documentation, you can extract this as an array, but my question is : what will the type of the array be, is it an array of Strings, name/value paired strings etc?
I'm creating some Java code that will take data out of this array, but I'm not sure which format it will be, such as 1, John OR 1=John or 1,John
Any ideas?
From the docs:
SQL>CREATE OR REPLACE TYPE EMPARRAY is VARRAY(20) OF VARCHAR2(30)
SQL>/
Then create the following function that returns a VARRAY.
CREATE OR REPLACE FUNCTION getEmpArray RETURN EMPARRAY
AS
l_data EmpArray := EmpArray();
CURSOR c_emp IS SELECT ename FROM EMP;
BEGIN
FOR emp_rec IN c_emp LOOP
l_data.extend;
l_data(l_data.count) := emp_rec.ename;
END LOOP;
RETURN l_data;
END;
It will return an array of strings (VARCHARs) max length 30
it returns emparray which is declared as a varray of varchars (strings)