Difference between STRPOS(Postgres) and CHARINDEX(MSSQL) For numeric Value - sql

Crate a table temp in both Postgres and SQL Server database.
create table temp (id numeric(10), name varchar(10));
insert into temp (id,name) values(10,'abc');
In MS SQL Server: select CHARINDEX('10',id) from temp (Success retrun 1)
In Postgres: select strpos('10',id) from temp
SQL Error [42883]: ERROR: function strpos(unknown, numeric) does not exist
Hint: No function matches the given name and argument types. You might need to add explicit type casts.
When I pass the parameter as numeric then get an error.
In SQL Server: select CHARINDEX(10,id) from temp;
SQL Error [8116] [S0001]: Argument data type int is invalid for argument 1 of charindex function.
There is a question simple that how second parameter implicitly converted to string in SQL Server, which column is numeric.
But for Postgres does not implicitly convert the value.
That's why I created a custom function but problem is same
CREATE OR REPLACE FUNCTION CHARINDEX(text, text, integer)
RETURNS integer
AS $$
SELECT CASE WHEN position(substr($2, $3+1)in $1) = 0 THEN 0 ELSE position(substr($2, $3+1)in $1) + $3 END;
$$
LANGUAGE SQL IMMUTABLE
RETURNS NULL ON NULL INPUT;
I search lots for datatype in CHARINDEX(MSSQL).
Need help for create such type of custom function which one accept all type as String.

Related

Column doesn't exist when using WITH statement PostgreSQL

I want to create a function to be used to get the node traversal path.
CREATE TYPE IDType AS (id uuid);
drop function F_ItemPath;
CREATE OR REPLACE FUNCTION F_ItemPath (item record)
RETURNS TABLE (item_id uuid, depth numeric)
AS $$
BEGIN
return QUERY
WITH recursive item_path AS (
SELECT ic.parent_item_id, depth=1
from item_combination ic, item i
WHERE ic.child_item_id=i.id
UNION all
SELECT ic.parent_item_id, depth=ip.depth + 1
FROM item_path ip, item_combination ic WHERE ip.parent_item_id=ic.child_item_id
)
SELECT item_id=ip.parent_item_id, depth=ip.depth FROM item_path ip;
END; $$
LANGUAGE plpgsql;
select * from F_ItemPath(('55D6F516-7D8F-4DF3-A4E5-1E3F505837A1', 'FFE2A4D3-267C-465F-B4B4-C7BB2582F1BC'))
there has two problems:
I tried using user-defined type to set parameter type CREATE TYPE IDType AS (id uuid);, but I don't know how to call the function with table argument
there has an error that says:
SQL Error [42703]: ERROR: column ip.depth does not exist
Where: PL/pgSQL function f_itempath(record) line 3 at RETURN QUERY
what I expected is I can use the function normally and the argument can be supplied from other tables.
this is the full query that you can try:
http://sqlfiddle.com/#!15/9caba/1
I made the query in DBEAVER app, it will have some different error message.
I suggest you can experiment with it outside sqlfiddle.
The expression depth=1 tests if the column depth equals the value 1 and returns a boolean value. But you never give that boolean expression a proper name.
Additionally you can't add numbers to boolean values, so the expression depth=ip.depth + 1 tries to add 1 to a value of true or false - which fails obviously. If it did work, it would then compare that value with the value in the column depth again.
Did you intend to alias the value 1 with the name depth? Then you need to use 1 as depth and ip.depth + 1 as depth in the recursive part.
In the final select you have the same error - using boolean expressions instead of a column alias
It's also highly recommended to use explicit JOIN operators which were introduced in the SQL standard over 30 years ago.
Using PL/pgSQL to wrap a SQL query is also a bit of an overkill. A SQL function is enough.
Using an untyped record as a parameter seems highly dubious. It won't allow you to access columns using e.g. item.id. But given your example call, it seems you simply want to pass multiple IDs for the anchor (no-recursive) part of the query. That's better done using an array or a varadic parameter which allows listing multiple parameters with commas.
So you probably want something like this:
drop function f_itempath;
CREATE OR REPLACE FUNCTION f_itempath(variadic p_root_id uuid[])
RETURNS TABLE (item_id uuid, depth integer)
as
$$
WITH recursive item_path AS (
SELECT ic.parent_item_id, 1 as depth
FROM item_combination ic
WHERE ic.child_item_id = any(p_root_id) --<< no join needed to access the parameter
UNION all
SELECT ic.parent_item_id, ip.depth + 1
FROM item_path ip
JOIN item_combination ic ON ip.parent_item_id = ic.child_item_id
)
SELECT ip.parent_item_id as item_id, ip.depth
FROM item_path ip;
$$
language sql
stable;
Then you can call it like this (note: no parentheses around the parameters)
select *
from f_itempath('55d6f516-7d8f-4df3-a4e5-1e3f505837a1', 'ffe2a4d3-267c-465f-b4b4-c7bb2582f1bc');
select *
from f_itempath('55d6f516-7d8f-4df3-a4e5-1e3f505837a1', 'ffe2a4d3-267c-465f-b4b4-c7bb2582f1bc', 'df366232-f200-4254-bad5-94e11ea35379');
select *
from f_itempath('55d6f516-7d8f-4df3-a4e5-1e3f505837a1');

Posgresql is trying to insert into GENERATED ALWAYS column

My table schema:
CREATE TABLE project_sectors(
sector_id int GENERATED ALWAYS AS IDENTITY,
sector_name varchar(256),
project_count int,
PRIMARY KEY (sector_id)
);
And I am trying to execute a query for many tables with some particular column name:
DO $$
DECLARE
t text;
BEGIN
FOR t IN
SELECT table_name FROM information_schema.columns WHERE column_name = 'project_name'
LOOP
RAISE NOTICE 'INSERT METADATA FOR: %', t;
EXECUTE 'INSERT INTO project_sectors VALUES ($1, 0)'
USING t;
end loop;
end
$$ language 'plpgsql';
Once I try to run the query I get:
[42804] ERROR: column "sector_id" is of type integer but expression is of type text Hint: You will need to rewrite or cast the expression. Where: PL/pgSQL function inline_code_block line 9 at EXECUTE
When previously the EXECUTE statement was
EXECUTE format('INSERT INTO megaproject_sectors VALUES (''%I'', 0)', t)
I would get the error
ERROR: invalid input syntax for type integer: "railway"
railway is the value of t.
Why is it trying to insert data into GENERATED ALWAYS column?
Why is it trying to insert data into GENERATED ALWAYS column?
Because you are not specifying the target columns in your INSERT statement, so Postgres uses them from left to right.
It is good coding practice to always specify the target columns. As your table name is hardcoded, the dynamic SQL is unnecessary as well:
INSERT INTO project_sectors (sector_name, sector_count) VALUES (t.table_name, 0)
Note that in other database products, specifying less values than the table has columns would result in an error. So in e.g. Oracle your statement would result in "ORA-00947: not enough values"

SQLExceptionHelper Invalid Input syntax for integer (PL/pgSQL)

I want to get an integer from a database query:
SELECT CAST(concat('id_',substr_of_jointable) AS INTEGER) into integervalue
FROM books_authors where id_books = booksvalue
ORDER BY id_books DESC
LIMIT 1;
subsr_of_jointable is a TEXT with value authors. However I always get an error:
ERROR org.hibernate.engine.jdbc.spi.SqlExceptionHelper - ERROR: invalid input syntax for integer: "id_authors"
Wobei: SQL statement "SELECT CAST(concat('id_',substr_of_jointable)AS INTEGER) FROM books_authors where id_books = books_value ORDER BY id_books DESC LIMIT 1"
PL/pgSQL function books_ins_trig_proc() line 125 at SQL statement
Does anyone have an idea why? The column id_books id_authors is an integer value in the database.
Assuming you're trying to build a dynamic query inside a PL/pgSQL function, you might want to take a look at this approach.
Data sample
CREATE TABLE t (id_authors INT);
INSERT INTO t VALUES (1);
Function
CREATE OR REPLACE FUNCTION myfunction(TEXT) RETURNS INT
LANGUAGE 'plpgsql' AS $BODY$
DECLARE i INT;
BEGIN
EXECUTE 'SELECT id_'|| $1 ||' FROM t LIMIT 1;' INTO i;
RETURN i;
END;
$BODY$;
This example is only to shows how you can concatenate your strings to create a column name inside your dynamic query.
Calling the function
SELECT * FROM myfunction('authors');
myfunction
------------
1
(1 Zeile)
Further reading:
Execute Dynamic Commands
PL/pgSQL Function Parameters

Creating functions in postgresql

I am new to SQL, so please try not to be overly critical about my question, I need to create a function which would return me a table (say for example "machine") , which would have a column called "aggtablename" and the rows would be filled with values derived from a database. Here is what i tried and the following error came....so please help me in making my syntax correct, THANKS..
CREATE FUNCTION aggtable() RETURNS TABLE (machineid, serveraggtablename)
AS $table$
BEGIN
RETURN QUERY
SELECT m.machineid, m.serveraggtablename
FROM machine m
END;
$table$
LANGUAGE plpgsql;
select aggtable();
ERROR: function aggtable() does not exist LINE 1: select aggtable();
^ HINT: No function matches the given name and argument types. You might need to add explicit type casts.
The arguments of the table you're returning do not have any type.
try adding a type such as machineid int.
check this post
How can a Postgres Stored Function return a table
Try this
CREATE TYPE machineType as (machineid int, serveraggtable character varying);
CREATE FUNCTION aggtable() RETURNS SETOF machineType AS
'SELECT m.machineid, m.serveraggtablename FROM machine m;'
LANGUAGE 'sql';
SELECT * FROM aggtable();
https://wiki.postgresql.org/wiki/Return_more_than_one_row_of_data_from_PL/pgSQL_functions

Stored Procedure / Stored Function: SELECT in PostgreSQL

I have created a stored procedure / function with a simple SELECT in PostgreSQL:
CREATE FUNCTION select_proc2()
RETURNS SETOF procedure AS
$DELIMETER$
SELECT * FROM procedure;
$DELIMETER$
LANGUAGE 'sql'
This one works but when I tried to be specific like this:
CREATE FUNCTION select_proc2(INT)
RETURNS SETOF procedure AS
$DELIMETER$
SELECT "Fname" FROM procedure where "Id" = $1;
$DELIMETER$
LANGUAGE 'sql'
it returns an error:
ERROR: return type mismatch in function declared to return procedure
DETAIL: Final statement returns character instead of integer at
column 1. CONTEXT: SQL function "select_proc2"
I tried any solution that I can think of. Anyone here know how to solve this error?
You need to adapt the RETURN type to what's actually returned:
CREATE OR REPLACE FUNCTION select_proc2(int)
RETURNS SETOF text AS
$func$
SELECT "Fname" FROM procedure WHERE "Id" = $1;
$func$ LANGUAGE sql
In your second version you only return one column. From the name I am deriving the data type text, but that's just a guess.
If "Id" is the primary key column of procedure or otherwise defined UNIQUE, only one row can be returned and you can simplify to:
RETURNS text
Also don't quote the language name. sql is an identifier here, not a string literal. It's only tolerated for historic reason, but it's probably going to be an error in future versions.
Concerning your column names: My advise is to use non-quoted lower-case identifiers exclusively in Postgres. Start by reading the chapter "Identifiers and Key Words" to learn about the significance of "id", "Id", ID or id as column name.
remove quotes around field names (without "):
CREATE FUNCTION select_proc2(INT)
RETURNS SETOF procedure AS
$DELIMETER$
SELECT Fname FROM procedure where Id = $1;
$DELIMETER$
LANGUAGE 'sql'