PostgresSQL 10.6 - function substring & regexp_matches function does not exist - sql

I have installed PostgresSQL 10.6 installed on Windows and using DBeaver - I confirmed the version by "SELECT VERSION()".
For some reason, whenever I try to use function SUBSTRING, I receive the below error:
SQL Error [42883]: ERROR: function pg_catalog.substring(character
varying, integer, character varying, integer) does not exist
Similarly for REGEXP_MATCHES
SQL Error [42883]: ERROR: function regexp_matches(character varying,
text, integer) does not exist Hint: No function matches the given
name and argument types. You might need to add explicit type casts.
The syntax I'm using I believe matches the docs, for example REGEXP_MATCHES(source_string, pattern, 1)
Any ideas why Postgres would throw these errors?

I was attempting to use the functions incorrectly which threw the "function doesn't exist". I guess it means that the function does exist if I want to use it with the type of parameters I tried to use.
REGEXP_MATCHES(source_string, pattern, 1) I understood to be a regex match with case insensitivty (1). As Nick Barnes pointed out in the comment, REGEXP_MATCHES takes (text,text,text).
I was shorterning the length of one text field to check if it existed within another column - rather than use SUBSTRING against col2, I used LEFT(col2,10) and instead of regexp_matches, I used (regexp_match(col1,col2))[1]

Related

Databricks Sql: Alternative to NCHAR() to replace characters

I have names in my table for which I need to replace certain characters with others.
I have the following code, but I get an error
REPLACE(REPLACE(TRIM(name),NCHAR(0x2019),NCHAR(0x0027)),NCHAR(0x200B),'')
However I get the following error message. Can somebody help me rewrite the code not using the Nchar function?
Undefined function: 'NCHAR'. This function is neither a registered temporary function nor a permanent function registered in the database 'default'
Instead of NCHAR function you can use unicode literals (\uXXXX) to represent a character as it's described in Spark documentation, in your case it will be:
REPLACE(REPLACE(TRIM(name),'\u2019','\u0027'),'\u200B','')

Stripping out non-digits - SQL0171 Argument of function TRANSLATE not valid

I'm trying to extract the first ten digit numbers of a phone number, ending up with a 10-digit (or less) number.
I need to use whitelisting, not blacklisting, due to special characters having been used. e.g. "á(123) 555-4567 Toll Free:á(891) 0" must become 1235554567.
I'm trying to use https://stackoverflow.com/a/37685384.
However, when I try to use this:
TRANSLATE(SFCONTACT.PHONE,'',TRANSLATE(SFCONTACT.PHONE,'','1234567890',''),'') as clean
I get
Message: [SQL0171] Argument 04 of function TRANSLATE not valid.
One of the comments said that using spaces instead of empty strings removed that. However, for me, trying:
TRANSLATE(SFCONTACT.PHONE,' ',TRANSLATE(SFCONTACT.PHONE,' ','1234567890',' '),' ') as clean
gives:
Message: [SQL0171] Argument 03 of function TRANSLATE not valid.
How can I accomplish this?
Running an AS400 DB2, IBM version V7R1M0
EDIT (Not sure if this should be a separate Question or not)
I tried this as suggested:
SUBSTR(REGEXP_REPLACE(PHONE, '[\D]', ''),1,10) AS MAINPHONE,
And at first it seemed to work; I was able to create a view, BBICNTMIG
However, when I try to insert into a table using that view:
INSERT INTO AMMLIBC.BBICONTACT
(COMPANY,CUSNO,SHIPTO,HONORIFICFK,FIRSTNAME,LASTNAME,EMAIL,MAINPHONE,TYPEFK,PROSPECTFK,CREATEDBY,CREATEDAT)
SELECT COMPANY,CUSNO,SHIPTO,HONORIFICFK,FIRSTNAME,LASTNAME,EMAIL,MAINPHONE,TYPEFK,PROSPECTFK,CREATEDBY,CREATEDAT
FROM AMMLIBC.BBICNTMIG
it gives:
Message: [SQL0420] Character in CAST argument not valid. Cause . . . . . : A character in the argument for the CAST function was not correct. Recovery . . . : Change the result data type to one that recognizes the characters in the CAST argument, or change the argument to contain a valid representation of a value for the result data type. Try the request again.
If I remove the phone numbers from the insert (taking default value of null instead), then the INSERT succeeds, so I know it's the phone number causing this.
The column type in the destination table is NUMERIC(10,0). I tried using this, but no change:
CAST(SUBSTR(REGEXP_REPLACE(PHONE, '[\D]', ''),1,10) AS NUMERIC(10,0)) AS MAINPHONE,
Further info:
I tried casting to char before casting to numeric. No change.
I tried adding a where clause (both "mainphone is null" and "mainphone is not null" do this) and the error message changes to:
Message: [SQL0802] Data conversion or data mapping error. Cause . . . . . : Error type 6 has occurred. [...] 6 -- Numeric data that is not valid.
The TRANSLATE function doesn't work correctly for non-ascii characters.
Use the following instead:
SELECT substr(
-- xmlcast(xmlquery('fn:replace($s, "[^\d]", "")' passing PHONE as "s") as varchar(4000)) -- DB2 for LUW
regexp_replace(PHONE, '[^\d]', '') -- DB2 for LUW 11.1 & DB2 for IBM i
, 1, 10)
FROM TABLE(VALUES
'á(123) 555-4567 Toll Free:á(891) 0'
, 'á(123) 555-'
) SFCONTACT(PHONE);
Platform & version of Db2 is important...
Db2 for i 7.2, for instance, gives me
Cause . . . . . : Parameter 3 specified in function TRANSLATE is not valid for use for reason code 1. The reason codes and their meanings follow:
1 -- Parameter must be a string constant.
2 -- Parameter must be an integer constant.
3 -- Parameter must be a numeric constant.
4 -- Parameter's length is too long.
5 -- Parameter's value is out of range.
6 -- Parameter must be a valid CCSID.
7 -- Parameter cannot be a parameter marker.
8 -- Parameter's data type is not supported by the built-in function.
9 -- Parameter cannot reference a column with an active column mask since the function is not secured.
Recovery . . . : Refer to the DB2 for IBM i SQL Reference topic collection in the Database category in the IBM i Information Center book, http://www.ibm.com/systems/i/infocenter/ for more information on functions. Correct the parameter specified for the function. Try the request again.
Using "FETCH FIRST _ ROWS ONLY" and binary search, I found the problem.
The phone number it was trying to parse was "PLEASE VERIFY CONTACT AND EMAIL". Which, stripping out digits, turns into empty string... which does not convert well into NUMERIC(10,0).
So, this fixed the problem:
CASE
WHEN TRIM(REGEXP_REPLACE(PHONE, '[\D]', '')) = '' THEN NULL
ELSE CAST(SUBSTR(REGEXP_REPLACE(PHONE, '[\D]', ''),1,10) AS NUMERIC(10,0))
END AS MAINPHONE,

ERROR: function regexp_matches(jsonb, unknown) does not exist in Tableau but works elsewhere

I have a column called "Bakery Activity" whose values are all JSONs that look like this:
{"flavors": [
{"d4js95-1cc5-4asn-asb48-1a781aa83": "chocolate"},
{"dc45n-jnsa9i-83ysg-81d4d7fae": "peanutButter"}],
"degreesToCook": 375,
"ingredients": {
"d4js95-1cc5-4asn-asb48-1a781aa83": [
"1nemw49-b9s88e-4750-bty0-bei8smr1eb",
"98h9nd8-3mo3-baef-2fe682n48d29"]
},
"numOfPiesBaked": 1,
"numberOfSlicesCreated": 6
}
I'm trying to extract the number of pies baked with a regex function in Tableau. Specifically, this one:
REGEXP_EXTRACT([Bakery Activity], '"numOfPiesBaked":"?([^\n,}]*)')
However, when I try to throw this calculated field into my text table, I get an error saying:
ERROR: function regexp_matches(jsonb, unknown) does not exist;
Error while executing the query
Worth noting is that my data source is PostgreSQL, which Tableau regex functions support; not all of my entries have numOfPiesBaked in them; when I run this in a simulator I get the correct extraction (actually, I get "numOfPiesBaked": 1" but removing the field name is a problem for another time).
What might be causing this error?
In short: Wrong data type, wrong function, wrong approach.
REGEXP_EXTRACT is obviously an abstraction layer of your client (Tableau), which is translated to regexp_matches() for Postgres. But that function expects text input. Since there is no assignment cast for jsonb -> text (for good reasons) you have to add an explicit cast to make it work, like:
SELECT regexp_matches("Bakery Activity"::text, '"numOfPiesBaked":"?([^\n,}]*)')
(The second argument can be an untyped string literal, Postgres function type resolution can defer the suitable data type text.)
Modern versions of Postgres also have regexp_match() returning a single row (unlike regexp_matches), which would seem like the better translation.
But regular expressions are the wrong approach to begin with.
Use the simple json/jsonb operator ->>:
SELECT "Bakery Activity"->>'numOfPiesBaked';
Returns '1' in your example.
If you know the value to be a valid integer, you can cast it right away:
SELECT ("Bakery Activity"->>'numOfPiesBaked')::int;
I found an easier way to handle JSONB data in Tableau.
Firstly, make a calculated field from the JSONB field and convert the field to a string by using str([FIELD_name]) command.
Then, on the calculated field, make another calculated field and use function:
REGEXP_EXTRACT([String_Field_Name], '"Key_to_be_extracted":"?([^\n,}]*)')
The required key-value pair will form the second caluculated field.

AnalysisException: Syntax error in line 1: error when taking modulus of a value using abs() in Impala

I want to take the modulus of a value when using Impala and I am aware of the abs() function. When I use this however like such
select abs(value) from table
It returns a value that is rounded to the nearest integer. The documentation found here states that I need to define the numeric_type. have tried this
select abs(float value) from table
but this gives me the following error
AnalysisException: Syntax error in line 1: ... abs(float value) from table ^ Encountered: FLOAT Expected: ALL, CASE, CAST, DEFAULT, DISTINCT, EXISTS, FALSE, IF, INTERVAL, NOT, NULL, TRUNCATE, TRUE, IDENTIFIER CAUSED BY: Exception: Syntax error
Any ideas how I set abs() to return a float?
This should work SELECT cast(Abs(-243.5) as float) AS AbsNum
I think you are misunderstanding the syntax. You call the function as abs(val). The return type is the same as the input type. It should work on integers, decimals, and floats.
If you want a particular type being returned, then you need to pass in that type, perhaps casting to the specific type.
The documentation is:
abs(numeric_type a)
Purpose: Returns the absolute value of the argument.
Return type: Same as the input value
Admittedly, this does look like the type should be part of the function call. But it is really using a programming language-style declaration to show the types that are expected.

postgresql send variables to a function, casting?

In one place I have
CREATE FUNCTION updateGeo2(text, float4, float4) RETURNS float AS $$
followed later by
SELECT updateGeo2('area', 40.88, -90.56);
and I get
error : ERROR: function updategeo2(unknown, numeric, numeric) does not exist
so it doesn't know that I tried to pass in a text variable, followed by a float variable and another float variable, it sees these as "unknown, numeric and numeric", lame. How do I let it know the types I am passing in?
try this way:
SELECT updateGeo2('area', (40.88)::float4, (-90.56)::float4);
Clarify misunderstanding
First of all, this should work as is, without type cast. I tested with PostgreSQL 9.1, 9.2 and also with 8.4.15. You must be running an earlier point-release or there is some other misunderstanding (like wrong search_path). Your information is misleading.
Except for ad-hoc calls, you should always add explicit type casts anyway to disambiguate. PostgreSQL allows function overloading. If another function should be created with the signature:
CREATE FUNCTION updateGeo2(text, numeric, numeric) RETURNS text AS $$ ..
... then it would take precedence over the other one due to the default type numeric for numeric literals. Existing code might break.
If, on the other hand, you add a function:
CREATE FUNCTION updateGeo2(char(5), numeric, numeric) RETURNS text AS $$ ..
Then Postgres does not know what to do any more and throws an exception:
ERROR: function updategeo2(unknown, numeric, numeric) is not unique
Proper syntax
SELECT updateGeo2('area', '40.88'::float4, '-90.56'::float4);
Or, more verbose in standard SQL:
SELECT updateGeo2('area', cast('40.88' AS float4), cast('-90.56' AS float4));
Or, if you really wanted to avoid single quotes (and colons):
SELECT updateGeo2('area', float4 '40.88', float4 '-90.56');
This way you cast a numeric literal to data type float4 (= real) directly.
More about type casting in the manual.
(40.88)::float4 works, too, but subtly less effective. First, 40.88 is taken to be of type numeric (the default type for this numeric literal containing a dot). Then the value is cast to float4. Makes two type casts.
More about numeric constants in the manual.