PervasiveSQL - Inserting/Updating record inside and If Else statement - sql

G'day. I'm trying to create a basic function which checks for the number of records matching a certain criteria. If there are none then it performs an insert and returns returns 0, otherwise it updates the existing record and returns 1. I'm getting a syntax error at the location of the Insert and Update statements. Here is my SQL script (FYI I'm new to pervasive and if anyone has a better way to perform an update/insert then I'm all ears/eyes):
CREATE FUNCTION "InsertUpdateWebData"(:KeyType CHAR(1), :KeyValue CHAR(50),
:WebData CHAR(100), :WhiteSpace LONGVARCHAR, :Spare CHAR(97)) RETURNS INTEGER
AS
BEGIN
DECLARE :RecordCount INTEGER;
SET :RecordCount = (SELECT COUNT(*) FROM SYS_WebData WHERE WBD_KeyType
= :KeyType and WBD_KeyValue = :KeyValue);
IF :RecordCount = 0 THEN
BEGIN
INSERT INTO SYS_WebData(WBD_KeyType, WBD_KeyValue, WBD_Data,
WBD_WhiteSpace, WBD_Spare) VALUES (:KeyType, :KeyValue, :WebData,
:WhiteSpace, :Spare);
RETURN 0;
END
ELSE
BEGIN
UPDATE SYS_WebData SET WBD_Data = :WebData, WBD_WhiteSpace = :WhiteSpace,
WBD_Spare = :Spare WHERE WBD_KeyType = :KeyType AND WBD_KeyValue =
:KeyValue;
RETURN 1;
END
END IF
END
What would be the correct syntax to do this?

From the Pervasive documentation:
Restrictions
You cannot use the CREATE DATABASE or the DROP DATABASE statement in a
user-defined function. The table actions CREATE, ALTER, UPDATE,
DELETE, and INSERT are not permitted within a user-defined function.
You should be able to change it from CREATE FUNCTION to CREATE PROCEDURE and have it work. I did that and it created the procedure.

Related

How to add error handling using SQL in snowflake

I've written below stored procedure code using SQL in snowflake which truncates a table and load new data into that table by first copying the data from a source, applying a bit of processing on it and loading into the target table which we truncated.
I've added nested Begin and End statements in order to try to add error handling functionality along with If Else statements but none of them worked. I want to first test if copy data was successful if yes than code should run second insert statements which basically brings data to staging where we refine the data where I want to add second check which checks if the rows were added successfully. Lastly we copy into the target table after all the checks are passed.
CREATE OR REPLACE PROCEDURE DEV_NMC_ITEM_AND_PSYCHOMETRIC_DM.STAGE2B."SP_N_1Test"("STAGE_S3" VARCHAR(16777216), "STAGE_OUTPUT" VARCHAR(16777216))
RETURNS VARCHAR(16777216)
LANGUAGE SQL
EXECUTE AS CALLER
AS '
DECLARE
Stage_nm_s3 STRING;
begin
truncate table "STAGE2A"."T001_IRF_STUDENT_FORM_S3";
execute immediate ''COPY INTO "STAGE2A"."T001_IRF_STUDENT_FORM_S3"
FROM ( select
a bunch of columns
from #stage2a.''||:STAGE_S3||'')
pattern= ''''.*_IRF_.*\\\\.csv''''
file_format = (type=csv, skip_header=1 )'';
begin
Insert into "STAGE2B"."T011_IRF_STUDENT_FORM_V001" (
a bunch of columns
SELECT
a bunch of columns
from "STAGE2A"."V001_IRF_STUDENT_FORM_T001";
begin
execute immediate ''copy into #stage2a.''||:STAGE_OUTPUT||''/T001_IRF_STUDENT_FORM_S3
from (SELECT
a bunch of columns
from "STAGE2B"."T011_IRF_STUDENT_FORM_V001")
file_format = ( format_name = F_CSV type=csv compression = none)
header = True
SINGLE = FALSE
OVERWRITE = TRUE
max_file_size=524288000 '';
return ''Load process completed for IRF_STUDENT_FORM_S3'';
end;
end;
end;
';```
I'm afraid you will need to wrap up your SQL statements into Javascript-syntax stored procedure to use Try/Catch block.
Here's some more explanation on that topic: Error handling for stored procedures

Prevent column change without the other

No-one should be allowed to update the customer address column unless the postcode column is also updated. If an attempt is made to update one without the other, then a trigger will fire and the user will be shown an error message.
Any help on how I can do this in Microsoft SQL Server 2012 will be appreciated!
You can use below logic
CREATE TRIGGER [dbo].AU_MyTrigger ON [dbo].MyTable
FOR UPDATE
AS
BEGIN
declare #bu_addr varchar(100)
declare #bu_zip varchar(100)
declare #au_addr varchar(100)
declare #au_zip varchar(100)
select #bu_addr = addr, #bu_zip = zip from DELETED
select #au_addr = addr, #ay_zip = zip from INSERTED
if (#bu_addr <> #au_addr) and (#bu_zip = #au_zip)
BEGIN
-- update table with old values
-- raise error
END
END
Note that if this update can happen in batch, you need to loop through each record and update their value to old and only return error at the end of trigger (outside of loop). In that case, for iterating on updated rows, you need to use CURSOR
You case might not be as easy as I explained, but this is the approach that works.

How to translate Sybase SQL to HSQLDB dialect?

I'd like to translate this very simple stored procedure from the Sybase SQL dialect to the HSQLDB dialect:
CREATE PROCEDURE dbo.some_proc
AS
BEGIN
SELECT int_param1 FROM control WHERE id_param = "SOME_PARAM" AND id_active = "Y"
END
In my humble opinion the documentation for HSQLDB is very mysterious about stored procedures. I couldn't find the right way to do it. I'm using HSQLDB version 2.3.1.
This can be expressed as a FUNCTION in HSQLDB
CREATE FUNCTION some_proc () RETURNS TABLE(VAL INT)
READS SQL DATA
BEGIN ATOMIC
RETURN TABLE(SELECT int_param1 FROM control WHERE id_param = 'SOME_PARAM' AND id_active = 'Y');
END
The function returns a single row table with all the values.
If your procedure always returns a single value, the declaration can be different to reflect this:
CREATE FUNCTION some_proc2 () RETURNS INT
READS SQL DATA
BEGIN ATOMIC
RETURN (SELECT int_param1 FROM control WHERE id_param = 'SOME_PARAM' AND id_active = 'Y');
END

SQL update if exist and insert else and return the key of the row

I have a table named WORD with the following columns
WORD_INDEX INT NOT NULL AUTO_INCREMENT,
CONTENT VARCHAR(255),
FREQUENCY INT
What I want to do is when I try to add a row to the table if a row with the same CONTENT exits, I want to increment the FREQUENCY by 1. Otherwise I want to add the row to the table. And then the WORD_INDEX in the newly inserted row or updated row must be returned.
I want to do this in H2 database from one query.
I have tried 'on duplicate key update', but this seems to be not working in H2.
PS- I can do this with 1st making a select query with CONTENT and if I get a empty result set, makeing insert query and otherwise making a update query. But as I have a very large number of words, I am trying to optimize the insert operation. So what I am trying to do is reducing the database interactions I am making.
Per your edited question .. you can achieve this using a stored procedure like below [A sample code]
DELIMITER $$
create procedure sp_insert_update_word(IN CONTENT_DATA VARCHAR(255),
IN FREQ INT, OUT Insert_Id INT)
as
begin
declare #rec_count int;
select #rec_count = count(*) from WORD where content = CONTENT_DATA;
IF(#rec_count > 0) THEN
UPDATE WORD SET FREQUENCY = FREQUENCY + 1 where CONTENT = CONTENT_DATA;
SELECT NULL INTO Insert_Id;
else
INSERT INTO WORD(CONTENT, FREQUENCY) VALUES(CONTENT_DATA, FREQ);
SELECT LAST_INSERT_ID() INTO Insert_Id;
END IF;
END$$
DELIMITER ;
Then call your procedure and select the returned inserted id like below
CALL sp_insert_update_word('some_content_data', 3, #Insert_Id);
SELECT #Insert_Id;
The above procedure code essentially just checking that, if the same content already exists then perform an UPDATE otherwise perform an INSERT. Finally return the newly generated auto increment ID if it's insert else return null.
First try to update frequency where content = "your submitted data here". If the affected row = 0 then insert a new row. You also might want make CONTENT unique considering it will always stored different data.

Using SELECT resultset to run UPDATE query with MySQL Stored Procedures

I'm trying to understand MySQL Stored Procedures, I want to check if a users login credentials are valid and if so, update the users online status:
-- DROP PROCEDURE IF EXISTS checkUser;
DELIMITER //
CREATE PROCEDURE checkUser(IN in_email VARCHAR(80), IN in_password VARCHAR(50))
BEGIN
SELECT id, name FROM users WHERE email = in_email AND password = in_password LIMIT 1;
-- If result is 1, UPDATE users SET online = 1 WHERE id = "result_id";
END //
DELIMITER ;
How Can I make this if-statement based on the resultsets number of rows == 1 or id IS NOT NULL?
DELIMITER //
CREATE PROCEDURE checkUser(IN in_email VARCHAR(80), IN in_password VARCHAR(50))
BEGIN
DECLARE tempId INT DEFAULT 0;
DECLARE tempName VARCHAR(50) DEFAULT NULL;
DECLARE done INT DEFAULT 0;
DECLARE cur CURSOR FOR
SELECT id, name FROM users WHERE email = in_email AND password = in_password;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
REPEAT
FETCH cur INTO tempId, tempName;
UPDATE users SET online = 1 WHERE id = tempId;
UNTIL done = 1 END REPEAT;
CLOSE cur;
SELECT tempName;
END //
DELIMITER ;
NB: I have not tested this. It's possible that MySQL doesn't like UPDATE against a table it currently has a cursor open for.
PS: You should reconsider how you're storing passwords.
Re comment about RETURN vs. OUT vs. result set:
RETURN is used only in stored functions, not stored procedures. Stored functions are used when you want to call the routine within another SQL expression.
SELECT LCASE( checkUserFunc(?, ?) );
You can use an OUT parameter, but you have to declare a user variable first to pass as that parameter. And then you have to select that user variable to get its value anyway.
SET #outparam = null;
CALL checkUser(?, ?, #outparam);
SELECT #outparam;
When returning result sets from a stored procedure, it's easiest to use a SELECT query.
Use:
UPDATE USERS
SET online = 1
WHERE EXISTS(SELECT NULL
FROM USERS t
WHERE t.email = IN_EMAIL
AND t.password = IN_PASSWORD
AND t.id = id)
AND id = 'result_id'
Why do you have LIMIT 1 on your SELECT? Do you really expect an email and password to be in the db more than once?
You could try an if statement if you have an result which returns 1
i looked at yor code, it seems nothing returns a true so you have to refactor it,
as above omg wrote thats realy true why do you have an limit 1 in your select query where only one emailadress can exisst?
something like this
update users set if(result==1,online=1,online=0) where email=emailadress