how to create function in postgres - sql

how to create function in PostgreSQL am using below code
create table sample(id int primary key)
create table sample2(id int primary key)
create view sampleall
As
select id from sample
union
select id from sample2
while creating below function for above tables
Create FUNCTION CheckFunction (ID INT)
RETURNS BIT AS
$$
BEGIN
IF EXISTS (SELECT 1 FROM sampleall WHERE id = #ID)
BEGIN
RETURN 1
END
RETURN 0
END
$$
LANGUAGE plpgsql;
CREATE TABLE sample3 (ID INT NOT NULL CONSTRAINT CHK_ID CHECK (dbo.CheckFunction(ID) = 1))
and getting below error
ERROR: syntax error at or near "BEGIN"
LINE 8: BEGIN
^
********** Error **********
ERROR: syntax error at or near "BEGIN"
SQL state: 42601
Character: 132
please help to solve the issue

As documented in the manual an IF requires a THEN. Additionally, parameters cannot be prefixed with a #. To avoid a name clash between a parameter name and a column name you should use a different name for the parameter. A common approach is to prefix parameters with p_
However your function is needlessly complex and can be simplified substantially if you return a proper boolean rather than a bit:
Create FUNCTION check_function (p_ID INT)
RETURNS boolean AS
$$
select exists (SELECT 1 FROM sampleall WHERE id = p_id);
$$
LANGUAGE sql;
Your check constraint can then be simplified to:
CREATE TABLE sample3 (ID INT NOT NULL CONSTRAINT CHK_ID CHECK (check_Function(ID));

Related

Can't use UDF as constraint in MariaDB

I'm running MariaDB 10.3.17 and I'm trying to add a constraint to an existing table. The constraint uses a UDF - which should be allowed.
Here's my table and UDF.
CREATE OR REPLACE TABLE real_estate.sample_two_expected_output (
u_id int (9) NOT NULL,
first_date date NOT NULL,
last_date date NOT NULL,
days int AS (DATEDIFF(last_date,first_date)+1),
address varchar(50),
price varchar(50),
--Constraints
CONSTRAINT dates CHECK (last_date >= first_date),
PRIMARY KEY (u_id,first_date));
DELIMITER //
USE real_estate;
CREATE OR REPLACE FUNCTION overlap(
u_id INT,
first_date DATE,
last_date DATE
) RETURNS INT DETERMINISTIC
BEGIN
DECLARE valid INT;
SET valid = 1;
IF EXISTS(SELECT * FROM real_estate.sample_two_expected_output t WHERE t.u_id = u_id AND first_date <= t.last_date AND t.first_date <= last_date) THEN SET valid = 0;
ELSE SET valid = 1;
END IF;
RETURN valid;
END; \\
DELIMITER;
I try to add this function as a constraint in the table.
ALTER TABLE real_estate.sample_two_expected_output ADD CONSTRAINT overlap CHECK(overlap(u_id,first_date,last_date)=1);
However I get the below error message and I don't know why.
EXECUTE FAIL:
ALTER TABLE real_estate.sample_two_expected_output ADD CONSTRAINT overlap CHECK(overlap(u_id,first_date,last_date)=1);
Message :
Function or expression '`overlap`()' cannot be used in the CHECK clause of `overlap`
In general you can use any deterministic user defined function (UDF) but not a stored function (SF) in constraints like DEFAULT, CHECK, etc.
A big difference between UDFs and SFs is the fact that a UDF is usually written in C/C++ while a SF is written in SQL. That means it is not possible to execute SQL code in a UDF within the same connection, which would lead to significant problems, as your SF shows:
Depending on the storage engine ALTER TABLE locks the entire table, parts of it or creates a temporary copy. I cannot imagine a way to execute the SQL statement SELECT * FROM real_estate.sample_two_expected_output t WHERE t.u_id = u_id .. in your SF while the table is locked or reorganized.

PostgreSQL syntax error at end of input not sure why

CREATE OR REPLACE FUNCTION customerGetByLargestSpend()
RETURNS TABLE(
customerID INTEGER,
firstName VARCHAR(20),
Surname VARCHAR(40),
totalBookings BIGINT,
totalSpend Numeric
)
ERROR: syntax error at end of input
LINE 8: )
^
SQL state: 42601
Character: 213
Not sure why this is happening.Any help would be very appreciated. thanks
The function is defined to return a row set, but does not return anything.
The parser expects to find something that returns rows, eg a select statement.
For example:
CREATE OR REPLACE FUNCTION customerGetByLargestSpend()
RETURNS TABLE(
customerID INTEGER,
firstName VARCHAR(20),
Surname VARCHAR(40),
totalBookings BIGINT,
totalSpend Numeric
)
AS $$ SELECT .... $$
LANGUAGE SQL

Can I use an SQL statement in assignment inside a PL/pgSQL function?

I've these two tables (Encomenda and Informacaofaturacao) and I'm trying to create a trigger to insert a new line on Informacaofaturacao before insert on Encomenda and put the ID of new line of Informacaofaturacao on new line of Encomenda.
What am I doing wrong?
Thanks
CREATE TABLE Encomenda
(
EncomendaID SERIAL,
ClienteID integer NOT NULL,
MoradaFaturacaoID integer NOT NULL,
MoradaEnvioID integer NOT NULL,
InformacaofaturacaoID integer NULL,
Data timestamp NOT NULL,
Estado EstadoEncomenda NOT NULL DEFAULT 'Em processamento',
CONSTRAINT PK_Encomenda PRIMARY KEY (EncomendaID)
)
;
CREATE TABLE Informacaofaturacao
(
InformacaofaturacaoID SERIAL,
MetodopagamentoID integer NULL,
Portes real NULL,
Iva real NULL,
Total real NULL,
CONSTRAINT PK_Informacaofaturacao PRIMARY KEY (InformacaofaturacaoID)
)
;
CREATE OR REPLACE FUNCTION insert_encomenda()
RETURNS TRIGGER
AS $$
BEGIN
NEW.InformacaofaturacaoID := (INSERT INTO Informacaofaturacao RETURNING InformacaofaturacaoID);
RETURN NEW;
END $$ LANGUAGE plpgsql;
CREATE TRIGGER insert_encomenda_trigger
BEFORE INSERT OR UPDATE ON Encomenda
FOR EACH ROW
EXECUTE PROCEDURE insert_encomenda();
Postgres doesn't accept a data modifying SQL statement (INSERT, UPDATE or DELETE) in assignment. The documentation states:
... the expression in such a statement is evaluated by means of an SQL SELECT command sent to the main database engine.
You should use this form of executing a query with a single-row result instead.
Also, INSERT command must have VALUES part, it can be: DEFAULT VALUES, VALUES(...) or query see the syntax in the documentation.
CREATE OR REPLACE FUNCTION insert_encomenda()
RETURNS TRIGGER
AS $$
BEGIN
INSERT INTO Informacaofaturacao(InformacaofaturacaoID)
VALUES(DEFAULT)
RETURNING InformacaofaturacaoID
INTO NEW.InformacaofaturacaoID;
RETURN NEW;
END $$ LANGUAGE plpgsql;

Searching a table using a user-defined function

I'm trying to write an SQL function that given a name of a game, it will allow me to search the table of games for that particular game and returns all the info about that game.
This is the code for the Games table:
CREATE TABLE Games(
game_id INT IDENTITY PRIMARY KEY,
name VARCHAR(50),
release_date VARCHAR(50),
rating VARCHAR(5),
min_age INT,
development_team_email VARCHAR(50) FOREIGN KEY REFERENCES Development_Teams,
release_conference INT FOREIGN KEY REFERENCES Conferences
)
And here is the what I could come up with when I was trying to write the function:
create function SearchGames(#game_name varchar(50))
returns table
begin
declare #game
Select (*)
From Games
where Games.name = #game_name
return #game
end
I'm getting a lot of syntax errors and I don't know what I'm doing wrong. Any help appreciated.
Use inline table valued function syntax and add schema:
create function dbo.SearchGames(#game_name varchar(50))
returns table
AS
RETURN (Select *
From Games
where Games.name = #game_name);
SqlFiddleDemo
If you use stored procedure you need to use:
CREATE TABLE ...;
INSERT INTO ... EXEC stored_procedure #args;
-- another operation on stored procedure resultset
while with inline table function you just:
SELECT * FROM dbo.SearchGames('aaa') GROUP BY ... HAVING ... ORDER BY;
I wouldn't recommend using a function for this, but rather a stored procedure:
Create Proc spSearchGames (#game_name Varchar (50))
As Begin
Select *
From Games
Where name = #game_name
End
Go
And executing it:
Exec spSearchGames 'YourGameName'

Executing script on Firebird error Token unknown - line 1, column 5 TERM. Error Code: -104

I am trying to write a script that creates a table, adds some constraints and then make a column auto-increment. As far as I read it happens with generator and before insert trigger.
Here is my code:
CREATE TABLE BLANKS
(
ID INT NOT NULL PRIMARY KEY,
BLANK_ID INT NOT NULL,
DATABASE_ID SMALLINT NOT NULL,
BLANK_VERSION DECIMAL,
CONSTRAINT ROW_UNIQUENESS UNIQUE(BLANK_ID, DATABASE_ID, BLANK_VERSION)
)
/* Autoincrement for field (ID) */
CREATE GENERATOR GEN_BLANKS_ID;
SET TERM ^ ;
CREATE TRIGGER BLANKS_BI FOR BLANKS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_BLANKS_ID,1);
END^
SET TERM ; ^
But it just doesn't work. It creates the table and the generator but when it reaches SET TERM ^ ; the script fails with error:
SQL Error: Dynamic SQL Error SQL error code = -104 Token unknown - line 1, column 5 TERM. Error Code: -104. can't format message 13:896 -- message file C:\Program Files (x86)\SQL Maestro Group\firebird.msg not found The SQL: SET TERM ^ ;
;
Do you have any suggestions?
Add a semicolon after the create table statement and remove the set term ^ syntax if your SQL client doesn't like it:
CREATE TABLE BLANKS
(
ID INT NOT NULL PRIMARY KEY,
BLANK_ID INT NOT NULL,
DATABASE_ID SMALLINT NOT NULL,
BLANK_VERSION DECIMAL,
CONSTRAINT ROW_UNIQUENESS UNIQUE(BLANK_ID, DATABASE_ID, BLANK_VERSION)
);
/* Autoincrement for field (ID) */
CREATE GENERATOR GEN_BLANKS_ID;
CREATE TRIGGER BLANKS_BI FOR BLANKS
ACTIVE BEFORE INSERT POSITION 0
AS
BEGIN
IF (NEW.ID IS NULL) THEN
NEW.ID = GEN_ID(GEN_BLANKS_ID,1);
END