Turn character varying column from null to 0 - postgresql

If I have a table like this:
How can I turn all NULL values to 0?
Using:
SELECT coalesce(area::text, 0) as area,
coalesce(duration::text, 0) as duration
But it keeps saying:
COALESCE types text and integer cannot be matched.

Related

How to limit the length of array text objects in PostgreSQL?

Is there any way to add a constraint on a column that is an array to limit length text objects?
I know that I can do this without constraint:
colA varchar(100)[] not null
I tried to do it in the following way:
alter table "tableA" ADD CONSTRAINT "colA_text_size"
CHECK ((SELECT max(length(pc)) from unnest(colA) as pc) <= 100) NOT VALID;
alter table "tableA" VALIDATE CONSTRAINT colA_text_size;
But got error: cannot use subquery in check constraint (SQLSTATE 0A000)
Try the following definition for your check constraint: (see demo, for demo I limit length to 25).
check (length(replace(array_to_string( text_array ,','), ',','')) <= 100)
What it does:
First the function array_to_string( ... ) converts the array to a csv.
The replace() function then removes the commas replacing them with the zero length string ''.
The length() function gets number of remaining characters in the string.
Finally that number is compared to the limit value (100) and the check constraint is either passed of failed.
References:
array_to_string(),
replace(), length()

Check if character varying is between range of numbers

I hava data in my database and i need to select all data where 1 column number is between 1-100.
Im having problems, because i cant use - between 1 and 100; Because that column is character varying, not integer. But all data are numbers (i cant change it to integer).
Code;
dst_db1.eachRow("Select length_to_fault from diags where length_to_fault between 1 AND 100")
Error - operator does not exist: character varying >= integer
Since your column supposed to contain numeric values but is defined as text (or version of text) there will be times when it does not i.e. You need 2 validations: that the column actually contains numeric data and that it falls into your value restriction. So add the following predicates to your query.
and length_to_fault ~ '^\+?\d+(\.\d*)?$'
and length_to_fault::numeric <# ('[1.0,100.0]')::numrange;
The first builds a regexp that insures the column is a valid floating point value. The second insures the numeric value fall within the specified numeric range. See fiddle.
I understand you cannot change the database, but this looks like a good place for a check constraint esp. if n/a is the only non-numeric are allowed. You may want to talk with your DBA ans see about the following constraint.
alter table diags
add constraint length_to_fault_check
check ( lower(length_to_fault) = 'n/a'
or ( length_to_fault ~ '^\+?\d+(\.\d*)?$'
and length_to_fault::numeric <# ('[1.0,100.0]')::numrange
)
);
Then your query need only check that:
lower(lenth_to_fault) != 'n/a'
The below PostgreSQL query will work
SELECT length_to_fault FROM diags WHERE regexp_replace(length_to_fault, '[\s+]', '', 'g')::numeric BETWEEN 1 AND 100;

Update with ISNULL and operation

original query looks like this :
UPDATE reponse_question_finale t1, reponse_question_finale t2 SET
t1.nb_question_repondu = (9-(ISNULL(t1.valeur_question_4)+ISNULL(t1.valeur_question_6)+ISNULL(t1.valeur_question_7)+ISNULL(t1.valeur_question_9))) WHERE t1.APPLICATION = t2.APPLICATION;
I know you cannot update 2 tables in a single query so i tried this :
UPDATE reponse_question_finale t1
SET nb_question_repondu = (9-(COALESCE(t1.valeur_question_4,'')::int+COALESCE(t1.valeur_question_6,'')::int+COALESCE(t1.valeur_question_7)::int+COALESCE(t1.valeur_question_9,'')::int))
WHERE t1.APPLICATION = t1.APPLICATION;
But this query gaves me an error : invalid input syntax for integer: ""
I saw that the Postgres equivalent to MySQL is COALESCE() so i think i'm on the good way here.
I also know you cannot add varchar to varchar so i tried to cast it to integer to do that. I'm not sure if i casted it correctly with parenthesis at the good place and regarding to error maybe i cannot cast to int with coalesce.
Last thing, i can certainly do a co-related sub-select to update my two tables but i'm a little lost at this point.
The output must be an integer matching the number of questions answered to a backup survey.
Any thoughts?
Thanks.
coalesce() returns the first non-null value from the list supplied. So, if the column value is null the expression COALESCE(t1.valeur_question_4,'') returns an empty string and that's why you get the error.
But it seems you want something completely different: you want check if the column is null (or empty) and then subtract a value if it is to count the number of non-null columns.
To return 1 if a value is not null or 0 if it isn't you can use:
(nullif(valeur_question_4, '') is null)::int
nullif returns null if the first value equals the second. The IS NULL condition returns a boolean (something that MySQL doesn't have) and that can be cast to an integer (where false will be cast to 0 and true to 1)
So the whole expression should be:
nb_question_repondu = 9 - (
(nullif(t1.valeur_question_4,'') is null)::int
+ (nullif(t1.valeur_question_6,'') is null)::int
+ (nullif(t1.valeur_question_7,'') is null)::int
+ (nullif(t1.valeur_question_9,'') is null)::int
)
Another option is to unpivot the columns and do a select on them in a sub-select:
update reponse_question_finale
set nb_question_repondu = (select count(*)
from (
values
(valeur_question_4),
(valeur_question_6),
(valeur_question_7),
(valeur_question_9)
) as t(q)
where nullif(trim(q),'') is not null);
Adding more columns to be considered is quite easy then, as you just need to add a single line to the values() clause

POSTGRES COALESCE(NULLIF(c.name,''), 'unassigned') not working

No version of a character varying field will return anything but NULL if there isn't a value... it's really frustrating
CASE WHEN COALESCE(NULLIF(e.name,''),'unassigned') IS NULL THEN 'unassigned' ELSE a.name END
was my final test and it still simply returns NULL unless the field has a value
it's character varying(255)
COALESCE(a.name,'unassigned') // won't work
NULLIF(a.name,'') // won't work
NULLIF(a.name,NULL) // won't work
COALESCE(NULLIF(a.name,''),'unassigned') // won't work
however the instant i use 0 it works..
what's up with that?
it's a character varying(255) field and it is set to default to null
as a matter of point the build of the table column is
name varying character(255) DEFAULT(NULL)
so I know it's entering NULL
and I've already done a
SELECT * FROM <tbl> WHERE name IS NULL; and of course, I return all the NULL rows with a.name... so what's the deal with this?
ok... to everyone deciding to answer me with:
COALESCE(NULLIF(e.name,''),'unassigned') IS NULL...
This method will never work on a return of "no records" and as this is a stored procedure which creates a materialized view, where I'm polling via nested queries - where it is possible for a column to have 0 (as the default id = other_id) the nested query would simply return no rows. When no row is returned, the functions of COALESCE or NULLIF would never execute. A row would have to be returned in order for those functions to act upon the row values... As I've never heard of a table with a PK auto-incremented field starting at 0 and generally starting at 1 the resultset of "no records returned" will always return a NULL value into the materialized view column.
The query I run afterward to poll rows from that materialized view will however function properly as COALESCE(etc etc) because now there is an actual NULL value in that column.

NULL Integer in multi-column in clause

I'm trying to run a multi-column in clause that matches null values as well. Right now I'm using coalesce like so:
select * from table
where (coalesce(foo, ''), coalesce(bar, '')) in (('foo_val', 'bar_val'), ('foo_val', ''));
For integer columns though, this throws 'invalid input syntax for integer: ""' on the coalesce. I could coalesce to -1 instead of an empty string, but was wondering if there was a more elegant solution.
Sample input/output:
Table data:
{{foo: 1, bar: 2}, {foo: 1, bar: NULL}}
User input: [(1, 2), (1, nil)]
Expected output: both rows.
EDIT: I'll try to clarify what I'm trying to do: I want to match DB rows by multiple column value combinations given by the user. That is, if the user inputs [(1,2), (3,4)], I'd want to return rows where column_A == 1 AND column_B == 2, OR column_A == 3 AND column_B == 4. Where I run into trouble is allowing for the user to input NULL and have it matched like any other value. So if the user inputs [(1,NULL)], I'd want to return rows where column_A == 1 AND column_B == NULL (but note I wouldn't want to return them for the previous query, since the user didn't specify he wanted rows with NULL values in column_B).
This code will not just match nulls, it will also match empty strings. If that's what you want, then fine.
Using a hard-coded list in an IN clause, where you wish to also return nulls, the simplest solution is to coalesce against the first value in your IN list. That way you don't have to worry about matching non-null values (like empty strings or -1) which aren't in the list.
select *
from table
where (coalesce(foo, 'foo_val'), coalesce(bar, 'foo_val'))
in (('foo_val', 'bar_val'), ('foo_val', ''));