I have PostgreSQL 9.6.8 running on Fedora 27 64bit. When i execute this query:
UPDATE tbl SET textsearchable_index_col =
setweight(to_tsvector('french', coalesce("col1",'')), 'D') ||
setweight(to_tsvector('french', coalesce("col2",'')), 'D');
I get this error:
ERROR: cache lookup failed for function 3625
********** Error **********
ERROR: cache lookup failed for function 3625
SQL state: XX000
but when I execute either:
UPDATE tbl SET textsearchable_index_col =
setweight(to_tsvector('french', coalesce("col1",'')), 'D');
or
UPDATE tbl SET textsearchable_index_col =
setweight(to_tsvector('french', coalesce("col2",'')), 'D');
I get:
Query returned successfully: 0 rows affected, 11 msec execution time.
My question is why does it work for either column individually but it does not work when together?
This link shows that it should be possible to use both columns in the same query (at the end of section 12.3.1).
Edit: here is what the system returns for Laurenz's queries. The first query returns
oprname | oprleft | oprright | oprcode
---------+----------+----------+----------
|| | tsvector | tsvector | 3625
The second query returns an empty result set.
Your database is corrupted, and you are lacking the function tsvector_concat which is the function behind the || operator.
This is how it should look on a healthy system:
SELECT oprname, oprleft::regtype, oprright::regtype, oprcode
FROM pg_operator
WHERE oid = 3633;
oprname | oprleft | oprright | oprcode
---------+----------+----------+-----------------
|| | tsvector | tsvector | tsvector_concat
(1 row)
SELECT proname, proargtypes::regtype[], prosrc
FROM pg_proc
WHERE oid = 3625;
proname | proargtypes | prosrc
-----------------+---------------------------+-----------------
tsvector_concat | [0:1]={tsvector,tsvector} | tsvector_concat
(1 row)
The second part is missing in your case.
You should restore from a backup.
Try to figure out how you got into this mess so that you can avoid it in the future.
Related
I need to convert some queries written for MariaDB to PostgreSQL syntax. Unfortunately they use the JSON_LENGTH function of MariaDB and im struggling to find an alternative with PostgreSQL.
For clarification:
JSON_LENGTH counts the number of 'entries' on the root level of a JSON object/array in MariaDB:
SELECT
JSON_LENGTH('{"test": 123}') as test1, -- 1
JSON_LENGTH('"123"') as test2, -- 1
JSON_LENGTH('123') as test3, -- 1
JSON_LENGTH('[]') as test4, -- 0
JSON_LENGTH('[123]') as test5, -- 1
JSON_LENGTH('[123, 456]') as test6, -- 2
JSON_LENGTH('[123, {"test": 123}]') as test7; -- 2
Partial solutions in PostgreSQL I came up with:
select
json_array_length('[]'::json) as test1, -- 0
json_array_length('["a"]'::json) as test2, -- 1
length(json_object_keys('{"a": "b"}'::json)) as test3; -- 1
json_array_length is not allowed for JSON objects
json_object_keys is not allowed for JSON arrays
Unfortunately I can't manage to combine the two methods I figured out for PostgreSQL:
I tried to use CASE WHEN:
select
case
when json_typeof('["a"]'::json) = 'array' then json_array_length('["a"]'::json)
when json_typeof('["a"]'::json) = 'object' then length(json_object_keys('["a"]'::json))
else 0
end;
Error:
[0A000] ERROR: set-returning functions are not allowed in CASE
-> json_object_keys is the bad guy here
I tried IF ELSE:
select
IF ('array' = json_typeof('["a"]'::json)) THEN json_array_length('["a"]'::json)
ELEIF (json_typeof('["a"]'::json) = 'object') THEN length(json_object_keys('["a"]'::json))
ELSE 0;
Error:
[42601] ERROR: syntax error at or near "THEN"
I can imagine I have an error in my IF ELSE statement, but I'm unable to figure it out.
Is there any way to replicate MariaDB's JSON_LENGTH behavior with PostgreSQL?
You need to count the number of rows returned by jsonb_object_keys():
This:
with data (input) as (
values
('{"test": 123}'::jsonb),
('"123"'),
('123'),
('[]'),
('[123]'),
('[123, 456]'),
('[123, {"test": 123}]')
)
select input,
case jsonb_typeof(input)
when 'array' then jsonb_array_length(input)
when 'object' then (select count(*) from jsonb_object_keys(input))
when 'string' then 1
else 0
end
from data
returns:
input | case
---------------------+-----
{"test": 123} | 1
"123" | 1
123 | 0
[] | 0
[123] | 1
[123, 456] | 2
[123, {"test": 123}] | 2
Of course this can easily be put into a function:
create or replace function my_json_length(p_input jsonb)
returns int
as
$$
select case jsonb_typeof(p_input)
when 'array' then jsonb_array_length(p_input)
when 'object' then (select count(*) from jsonb_object_keys(p_input))
when 'string' then 1
else 0
end;
$$
language sql
immutable;
I would not name it json_length() to avoid any clashes in case Postgres decides to implement such a function in the future (although I am not aware of such a function in the SQL standard).
Note that jsonb is the recommended data type to store JSON values in Postgres.
in order to create a more complex custom aggregate function, i followed first this amazing tutorial.
Here the data i use :
create table entries(
id serial primary key,
amount float8 not null
);
select setseed(0);
insert into entries(amount)
select (2000 * random()) - 1000
from generate_series(1, 1000000);
So I have this table :
id | amount | running_total
---------+-----------------------+--------------------
1 | -462.016298435628 | -462.016298435628
2 | 162.440904416144 | -299.575394019485
3 | -820.292402990162 | -1119.86779700965
4 | -866.230697371066 | -1986.09849438071
5 | -495.30001822859 | -2481.3985126093
6 | 772.393747232854 | -1709.00476537645
7 | -323.866365477443 | -2032.87113085389
8 | -856.917716562748 | -2889.78884741664
9 | 285.323366522789 | -2604.46548089385
10 | -867.916810326278 | -3472.38229122013
-- snip --
And I would like the max of the running_total column
(I know I can do do it without a new aggregate function, but it's for the demonstration)
So i've made this aggregate function
create or replace function grt_sfunc(agg_state point, el float8)
returns point
immutable
language plpgsql
as $$
declare
greatest_sum float8;
current_sum float8;
begin
current_sum := agg_state[0] + el;
greatest_sum := 40;
/*if agg_state[1] < current_sum then
greatest_sum := current_sum;
else
greatest_sum := agg_state[1];
end if;*/
return point(current_sum, greatest_sum);
/*return point(3.14159, 0);*/
end;
$$;
create or replace function grt_finalfunc(agg_state point)
returns float8
immutable
strict
language plpgsql
as $$
begin
return agg_state[0];
end;
$$;
create or replace aggregate greatest_running_total (float8)
(
sfunc = grt_sfunc,
stype = point,
finalfunc = grt_finalfunc
);
Normally it sould work, but in the end, it gives me a null result :
select greatest_running_total(amount order by id asc)
from entries;
id | running_total
---------+---------------
1 | [NULL]
I tried to change the type of the data, to check the 2 first aggregate functions separately, they are working well. Does someone could help me find a solution please ? :)
Thank you very much !
You need to set a non-NULL initcond for the aggregate. Presumably that would be (0,0), or maybe negative very large numbers for each? Or manually check for the agg_state being NULL.
Also, it seems like your grt_finalfunc should be returning subscript [1], not [0].
So, the solution was to add an initial condition. Indeed, without initial condition, the first value is considered as NULL :D (thank you #jjanes and #The Impaler)
So I corrected ma aggregated function :
create or replace aggregate greatest_running_total (float8)
(
sfunc = grt_sfunc,
stype = point,
finalfunc = grt_finalfunc,
initcond = '(0,0)'
);
And, indeed SQL indexes its tables from 1 and not from 0... Here was my second mistake,
Thank you very much !!
So I have a lot of data like this:
pix11co;10.115.0.1
devapp087co;10.115.0.100
old_main-mgr;10.115.0.101
radius03co;10.115.0.110
And I want to delete the stuff after the ; so it just becomes
pix11co
devapp087co
old_main-mgr
radius03co
Since they're all different I can live with the semi-colon staying there.
I have the following query and it runs successfully but doesn't delete anything.
UPDATE dns$ SET [Name;] = REPLACE ([Name;], '%_;%__________%', '%_;');
What wildcards can I use to specify the characters after the ; ?
Can you use CHARINDEX? E.g.:
SELECT LEFT('pix11co;10.115.0.1', CHARINDEX(';', 'pix11co;10.115.0.1') - 1)
You can use SUBSTRING() and CHARINDEX() functions:
CREATE TABLE MyStrings (
STR VARCHAR(MAX)
);
INSERT INTO MyStrings VALUES
('pix11co;10.115.0.1'),
('devapp087co;10.115.0.100'),
('old_main-mgr;10.115.0.101'),
('radius03co;10.115.0.110');
SELECT STR, SUBSTRING(STR, 1, CHARINDEX(';', STR) -1 ) AS Result
FROM MyStrings;
Results:
+---------------------------+--------------+
| STR | Result |
+---------------------------+--------------+
| pix11co;10.115.0.1 | pix11co |
| devapp087co;10.115.0.100 | devapp087co |
| old_main-mgr;10.115.0.101 | old_main-mgr |
| radius03co;10.115.0.110 | radius03co |
+---------------------------+--------------+
In my database I have a table "Datapoint" with the two columns "Id" (integer) and "Description" (character varying). Table "Datapoint"
I then have a table "Logging" with the three columns "Id" (integer), "Dt" (timestamp without timezone) and "Value" (double precision).Table "Logging"
I also have the following function:
CREATE OR REPLACE FUNCTION count_estimate(query text)
RETURNS integer AS
$BODY$ DECLARE rec record;ROWS INTEGER;BEGIN FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP ROWS := SUBSTRING(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');EXIT WHEN ROWS IS NOT NULL;END LOOP;RETURN ROWS;END $BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
This function returns the estimated count of entries that are found by a SELECT-Query, e.g. SELECT count_estimate('SELECT * FROM "Logging" WHERE "Id" = 3') would return 2.
I would now like to combine a SELECT-query on the table "Datapoint" with the return value of my function, so that my result looks like this:
ID | Description | EstimatedCount
1 | Datapoint 1 | 3
2 | Datapoint 2 | 4
3 | Datapoint 3 | 2
4 | Datapoint 4 | 1
My SELECT-query should look something like this:
SELECT
"Datapoint"."Id",
"Datapoint"."Description",
(SELECT count_estimate ('SELECT * FROM "Logging" WHERE "Logging"."Id" = "Datapoint"."Id"')) AS "EstimatedCount"
FROM
"Datapoint"
So my problem is to write a functioning SELECT-query for my purposes.
What about:
SELECT
"Datapoint"."Id",
"Datapoint"."Description",
count_estimate ('SELECT * FROM "Logging" WHERE "Logging"."Id" = "Datapoint"."Id"') AS "EstimatedCount"
FROM
"Datapoint"
You almost got it right, except that you need to supply the value of "Datapoint"."Id":
SELECT
"Datapoint"."Id",
"Datapoint"."Description",
count_estimate(
'SELECT * FROM "Logging" WHERE "Logging"."Id" = ' || "Datapoint"."Id"
) AS "EstimatedCount"
FROM "Datapoint";
Trying to run sha256 function
CREATE EXTENSION pgcrypto;
CREATE OR REPLACE FUNCTION sha256(bytea) returns text AS $$
SELECT encode(digest($1, 'sha256'), 'hex')
$$ LANGUAGE SQL STRICT IMMUTABLE;
WITH
tab_email as (SELECT 'my#email.com'::text as email FROM tmp),
INSERT INTO users (email, password) VALUES ((SELECT email FROM tab_email), sha256('mypass'));
i got this error
ERROR: function sha256(text) does not exist
It's because Postgres's built-in sha256 function takes a bytea argument:
citus=> \df+ sha256
List of functions
Schema | Name | Result data type | Argument data types | Type | Volatility | Parallel | Owner | Security | Access privileges | Language | Source code | Description
------------+--------+------------------+---------------------+------+------------+----------+----------+----------+-------------------+----------+--------------+--------------
pg_catalog | sha256 | bytea | bytea | func | immutable | safe | postgres | invoker | | internal | sha256_bytea | SHA-256 hash
(1 row)
So just cast to ::bytea first.
citus=> select encode(sha256('a'::bytea), 'hex');
encode
------------------------------------------------------------------
ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb
(1 row)
I ended up using
encode(digest(password, 'sha256'), 'hex') from tab_password)
If you create this function in redshift, you will be able to your f_sha256
CREATE OR REPLACE FUNCTION f_sha256 (mes VARCHAR)
returns VARCHAR
STABLE AS $$
import hashlib
return hashlib.sha256(mes).hexdigest()
$$ language plpythonu;