Error in syntax of define a trigger in SQLite - sqlite

In a table as below:
CREATE TABLE "active_mtrs"
(
"mtr_ID" INTEGER PRIMARY KEY NOT NULL,
"status" INTEGER,
"NIrSTime" DATETIME,
"NIrETime" DATETIME
)
I defined a trigger as:
CREATE TRIGGER "main"."replace1"
AFTER INSERT ON "active_mtrs" FOR EACH ROW
BEGIN
DECLARE #NIrSTime DATETIME;
DECLARE #NIrETime DATETIME;
DECLARE #mtr_ID INTEGER DEFAULT 0;
SELECT #mtr_ID = mtr_ID FROM INSERTED;
SELECT #NIrSTime = NIrSTime,#NIrETime = NIrETime
FROM subscriber
WHERE mtr_ID = #mtr_ID;
UPDATE active_mtrs
SET NIrSTime = #NIrSTime,
NIrETime = #NIrETime
WHERE mtr_ID = #mtr_ID;
END
where subscriber is another table in this database.
But I get an error:
[ near "DECLARE": syntax error ]
Exception Name: NS_ERROR_FAILURE
Exception Message: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE)
What is my problem?

Your problem is that you are trying to use a different SQL dialect in SQLite.
You cannot use DECLARE; you have to look up the values directly:
CREATE TRIGGER main.replace1
AFTER INSERT ON active_mtrs
FOR EACH ROW
BEGIN
UPDATE active_mtrs
SET (NIrSTime, NIrETime) =
(SELECT NIrSTime, NIrETime
FROM subscriber
WHERE mtr_ID = NEW.mtr_ID)
WHERE mtr_ID = NEW.mtr_ID;
END;

Related

Recursive stored procedure in HSQLDB

is it possible to create recursive stored procedure in HSQLDB ?
I wrote the following one to update a record and recursively all the parent records:
CREATE PROCEDURE updateFolderTotals(IN p_id VARCHAR(32), IN p_size BIGINT, IN p_files INT, IN p_folders INT)
MODIFIES SQL DATA
BEGIN ATOMIC
DECLARE l_parentid VARCHAR(32);
UPDATE folders
SET tot_files = tot_files + p_files,
tot_size = tot_size + p_size ,
tot_folders = tot_folders + p_folders
WHERE id = p_id;
SELECT parentid INTO l_parentid FROM folders WHERE id = p_id;
IF (l_parentid IS NOT NULL) THEN
CALL updateFolderTotals(l_parentid,p_size,p_files,p_folders);
END IF;
END;
but I get the following error:
user lacks privilege or object not found: UPDATEFOLDERTOTALS / Error Code: -5501 / State: 42501
In HyperSQL User Guide I've found some info (see Recursive Routines in HyperSQL User Guide) but it seems it is supported for funtions only.
Thank you in advance for support.
You can create recursive procedures following the same guidelines. First create the procedure with a simple body that throws an exception. You need to specify the SPECIFIC name of the procedure:
CREATE PROCEDURE updateFolderTotals(IN p_id VARCHAR(32), IN p_size BIGINT, IN p_files INT, IN p_folders INT)
SPECIFIC updateFolderTotals_1 MODIFIES SQL DATA
SIGNAL SQLSTATE '45000'
Then alter the created procedure with the full body:
ALTER SPECIFIC ROUTINE updateFolderTotals_1
BEGIN ATOMIC
DECLARE l_parentid VARCHAR(32);
UPDATE folders
SET tot_files = tot_files + p_files,
tot_size = tot_size + p_size ,
tot_folders = tot_folders + p_folders
WHERE id = p_id;
SELECT parentid INTO l_parentid FROM folders WHERE id = p_id;
IF (l_parentid IS NOT NULL) THEN
CALL updateFolderTotals(l_parentid,p_size,p_files,p_folders);
END IF;
END;

MariaDB pl/sql to populate a table with dates from '1990-01-01' to '2000-12-31'

I attempt to create a procedure or function to populate a table name Time_Dim in MariaDB.
DELIMITER /
CREATE FUNCTION filltimeDim ()
BEGIN
DECLARE vQuarter VARCHAR(6);
DECLARE vMonth_Name VARCHAR(20);
DECLARE vdate_id date;
DECLARE vyear_id CHAR(4);
DECLARE vweekly_Name VARCHAR(20);
DECLARE vMonth_Num TINYINT(10);
DECLARE vweekday_Num TINYINT(10);
BEGIN
SET vdate_id = CONVERT('1998-01-01', DATE);
WHILE (CONVERT('vdate_id' USING utf8) <= '2002-12-31')
LOOP
SET vyear_id = YEAR(vdate_id);
SET vQuarter = QUARTER(vdate_id);
SET vMonth_Name = MONTHNAME(vdate_id);
SET vweekly_Name = DAYOFWEEK(vdate_id);
SET vMonth_Num = MONTH(vdate_id);
SET vweekday_Num = WEEKDAY(vdate_id);
INSERT INTO Time_Dim VALUES
(vdate_id, vyear_id, vquarter, vMonth_Name,vweekly_Name,vMonth_Num,vweekday_Num);
SET vdate_id = vdate_id + 1;
END LOOP;
END;
END; /
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'LOOP
SET vyear_id = YEAR(vdate_id);
SET vQuarter = QUA' at line 13
The syntax for while in MariaDB is:
[begin_label:] WHILE search_condition DO
statement_list
END WHILE [end_label]
https://mariadb.com/kb/en/library/while/
You shouldn't use the 'LOOP' keywords
You can use Sequence Storage Engine:
-- SELECT
-- DATEDIFF('2002-12-31', '1990-01-01'); -- 4747
INSERT INTO `Time_Dim` (
`vdate_id`,
`vyear_id`,
`vquarter`,
`vMonth_Name`,
`vweekly_Name`,
`vMonth_Num`,
`vweekday_Num`
)
SELECT
`der`.`day`,
YEAR(`der`.`day`),
QUARTER(`der`.`day`),
MONTHNAME(`der`.`day`),
DAYOFWEEK(`der`.`day`),
MONTH(`der`.`day`),
WEEKDAY(`der`.`day`)
FROM (
SELECT
'1990-01-01' + INTERVAL (`seq`) DAY `day`
FROM
`seq_0_to_4747`
) `der`;
See dbfiddle.

how can i call stored procedure from the function in mariadb?

i want to get count of no.of rows present in table which i pass at runtime to a function.
i have created a procedure and function to execute dynamic queries. function will not allow dynamic query because i am calling procedure from function.
that procedure having dynamic query.
///////procedure///////
CREATE PROCEDURE bizopsgolddev.`test1`(tbnm varchar(100))
begin
declare sql_text varchar(200);
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
SELECT CONCAT(sql_text, ' is not valid');
END;
set sql_text=concat('select count(*) from ',tbnm);
SET #SQL := sql_text;
PREPARE stmt FROM #SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
end;
//////function//////
DROP FUNCTION IF EXISTS xyz;
CREATE FUNCTION `xyz`(tname varchar(100)) RETURNS int(11)
begin
declare val int;
call test1(tname);
return 1;
end;
if i execute this //select xyz('axpdc')// it should return rows count
can any one tell me how can i get count by passing table name to function(in mariadb only)
As I understand the question, the solution would be a function that returns the row count of a table with it's name passed to the function as a parameter.
I think this could be done by querying the information_schema database in MariaDB. A function could look like this:
CREATE DEFINER = 'yourUsername'#'192.168.%'
FUNCTION testDataBase.fn_GetRowCount(tableName VARCHAR(128))
RETURNS int(11)
BEGIN
-- This could be a parameter if need it to be.
DECLARE databaseName varchar(40) DEFAULT 'testDataBase';
DECLARE result int DEFAULT -1;
SELECT t.TABLE_ROWS INTO result
FROM information_schema.TABLES t
WHERE t.TABLE_NAME = tableName
AND t.TABLE_SCHEMA = databaseName;
RETURN result;
END
In order for this to work the user mentioned as the definer must have read privilege to the TABLES table in the information_schema database, otherwise you might get an error (tbh, I don't know if this is necessary).
There is a lot of useful information to be grabbed from the information_schema database.

An unexpected token "EXCEPTION" was found In PL/SQL(DB2)

I am Wrting a Stored Function As below in db2.
CREATE OR replace FUNCTION moc_enddate( IN v_date VARCHAR(6),
IN v_message VARCHAR(20)) returns DATE
BEGIN
DECLARE v_temp DATE;
DECLARE v_end_date DATE;
DECLARE v_temp_string VARCHAR(8) DEFAULT '01';
SET v_temp_string = v_temp_string
|| v_date;
SET v_temp = to_date(v_temp_string,'DDMMYYYY');
SET v_end_date = (v_temp + 19 days);
RETURN v_end_date;
EXCEPTION
WHEN no_data_found THEN
SET v_message = 'SqlDataException';
WHEN OTHERS THEN
SET v_message = 'OTHER';
END;
But I am getting the following Exception.
ERROR [42601] [IBM][DB2/AIX64] SQL0104N An unexpected token "EXCEPTION" was found following "RN V_END_MOC_DATE; ". Expected tokens may include.
"<psm_case>".
Maybe, you are using DB2 SQL PL instead of PL/SQL. There is a difference between these languages. If it's the case, the following condition should work:
create or replace procedure CreatePlants
begin
declare sqlstate char(5) default '00000';
declare ErrorMsg varchar(96);
declare exit handler for sqlexception
begin
set ErrorMsg = 'SQLSTATE=' concat sqlstate;
signal sqlstate '99001'
set message_text = ErrorMsg;
end;
create table plants
( ID dec(3), Location varchar(16),
primary key (ID));
label on table plants is 'Plant master';
insert into plants values
( 1, 'Lost Angeles'),
( 2, 'New Yolk'),
( 3, 'Last Vegas');
end
For more references see:
Error Handling in SQL PL, Part 1
Determine The State Of The Error

SQL use comma-separated values with IN clause

I am developing an ASP.NET application and passing a string value like "1,2,3,4" into a procedure to select those values which are IN (1,2,3,4) but its saying "Conversion failed when converting the varchar value '1,2,3,4' to data type int."
Here is the aspx code:
private void fillRoles()
{
/*Read in User Profile Data from database */
Database db = DatabaseFactory.CreateDatabase();
DbCommand cmd = db.GetStoredProcCommand("sp_getUserRoles");
db.AddInParameter(cmd, "#pGroupIDs", System.Data.DbType.String);
db.SetParameterValue(cmd, "#pGroupIDs", "1,2,3,4");
IDataReader reader = db.ExecuteReader(cmd);
DropDownListRole.DataTextField = "Group";
DropDownListRole.DataValueField = "ID";
while (reader.Read())
{
DropDownListRole.Items.Add((new ListItem(reader[1].ToString(), reader[0].ToString())));
}
reader.Close();
}
Here is my procedure:
CREATE Procedure [dbo].[sp_getUserRoles](#pGroupIDs varchar(50))
AS BEGIN
SELECT * FROM CheckList_Groups Where id in (#pGroupIDs)
END
Here is a workaround I found to do what you are trying to achieve
CREATE Procedure [dbo].[sp_getUserRoles](
#pGroupIDs varchar(50)
)
As
BEGIN
SELECT * FROM CheckList_Groups Where (',' + #pGroupIDs +',' LIKE '%,' + CONVERT(VARCHAR, id) + ',%')
End
This gets your comma delimited list and compares it to the id's(which are represented like so ',1,', ',2,' etc) in the table using LIKE
If you dont want to use dynamic sql, the best way ive found is to create a function which turns a delimited string into a table, something like this works for an Integer list:
CREATE FUNCTION [dbo].[StringToIntList]
(#str VARCHAR (MAX), #delimeter CHAR (1))
RETURNS
#result TABLE (
[ID] INT NULL)
AS
BEGIN
DECLARE #x XML
SET #x = '<t>' + REPLACE(#str, #delimeter, '</t><t>') + '</t>'
INSERT INTO #result
SELECT DISTINCT x.i.value('.', 'int') AS token
FROM #x.nodes('//t') x(i)
ORDER BY 1
RETURN
END
Then use that in your sp:
CREATE Procedure [dbo].[sp_getUserRoles](
#pGroupIDs varchar(50)
)
As
BEGIN
SELECT * FROM CheckList_Groups Where id in (
SELECT ID FROM dbo.StringToIntList(#pGroupIds,',')
)
End
Sure it can't do that,
The generated query would be sth like this
SELECT * FROM CheckList_Groups Where id in ('1,2,3,4')
and sure it can't be executed.
you can build the query in your stored procedure then execute it with exec
'SELECT * FROM CheckList_Groups Where id in (' + #pGroupIDs + ')'
or
SELECT * FROM CheckList_Groups Where charindex(','+id+',' , #pGroupIDs)>0
but you first must add the ',' to start and end of your parameter in your c# code
It is not possible to put those values (the comma separated string) in a parameter-value.
What you'll have to do, is to create the SQL Statement in your stored procedure dynamically, by string concatenation. You'll have to execute it with the sp_executesql stored procedure then.
CREATE PROCEDURE [dbo].[getUserRoles]( #groupIds NVARCHAR(50) )
AS BEGIN
DECLARE #statement NVARCHAR(255)
SELECT #statement = N'SELECT * FROM CheckList_Groups Where id in ( ' + #pGroupIDs + N')'
execute sp_executesql #statement
END
Also, not that I named the SP getUserRoles instead of sp_getUserRoles.
The reason is very simple: when you execute a stored procedure whose name starts with sp_, then SQL Server will first query the master database to find that stored procedure, which causes a performance hit offcourse.
The way you are trying to do this is slightly wrong. You will need to use EXECUTE in order to achieve this.
CREATE PROCEDURE [dbo].[sp_getUserRoles](#pGroupIDs nvarchar(50))
As
BEGIN
EXECUTE (N'SELECT * FROM CheckList_Groups Where id in (' + #pGroupIDs + ')';
END
DECLARE #TagId NVARCHAR(100) = '43,81'
SELECT * FROM TABLE WHERE TagId IN (SELECT TRIM(VALUE) FROM STRING_SPLIT( #TagId , ',' ) )
USE STRING_SPLIT FUNCTION FOR THIS
You need to use SP_executesql to achieve this functionllity
CREATE Procedure [dbo].[sp_getUserRoles](
#pGroupIDs varchar(50)
)
As
BEGIN
EXECUTE sp_executesql
N'SELECT * FROM CheckList_Groups Where id in (#pGroupIDs)',
N'#level varchar(50)',
#level = #pGroupIDs;
End
The IN clause can't take a bound parameter like that. What it's being given when the query is actually created is SELECT * FROM CheckList_Groups Where id in ('1,2,3,4'). Essentially the IN clause is being passed a single string.
First create function -
Just run this code
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [dbo].[CSVToTable] (#InStr VARCHAR(MAX))
RETURNS #TempTab TABLE
(id int not null)
AS
BEGIN
;-- Ensure input ends with comma
SET #InStr = REPLACE(#InStr + ',', ',,', ',')
DECLARE #SP INT
DECLARE #VALUE VARCHAR(1000)
WHILE PATINDEX('%,%', #INSTR ) <> 0
BEGIN
SELECT #SP = PATINDEX('%,%',#INSTR)
SELECT #VALUE = LEFT(#INSTR , #SP - 1)
SELECT #INSTR = STUFF(#INSTR, 1, #SP, '')
INSERT INTO #TempTab(id) VALUES (#VALUE)
END
RETURN
END
GO
Then -
Use function in bracket with select statment -
DECLARE #LIST VARCHAR(200)
SET #LIST = '1,3'
SELECT Id, Descr FROM CSVDemo WHERE Id IN (SELECT * FROM dbo.CSVToTable(#LIST))

Resources