Does SQLite have Cursors? - sqlite

i wonder if i could run the following procedure in SQLite:
set nocount on
select T.ID, max(T.SerialNo) as SerialNo
into #Tmp_Ticket_ID
from Ticket as T, Ticket as inserted
where t.ID = inserted.ID
group by T.id having count(*) > 1
declare zeiger cursor for
select SerialNo
from #Tmp_Ticket_ID
declare #SerialNo int
OPEN Zeiger
FETCH NEXT FROM zeiger INTO #SerialNo
WHILE (##fetch_status <> -1)
BEGIN
IF (##fetch_status <> -2)
BEGIN
update T
set ID = (select max(id) + 1 from Ticket)
from ticket AS T, #Tmp_Ticket_ID as I
where t.serialNo = i.serialno
and I.Serialno = #SerialNo
END
FETCH NEXT FROM zeiger INTO #SerialNo
END
CLOSE Zeiger
DEALLOCATE Zeiger
DROP TABLE #Tmp_Ticket_ID
This is a little procedure from a ms-sql2000 which cleans doubles of Ticket_id's in a given table Ticket of the following structur:
create table Ticket (serialNo int identity(1,1) not null
, ID as int not null
, Ticket_issue as varchar(50)
, some_more_field varchar(500))
Due to a simple merger from different databases, the ticket_id's becomes not unique. To fix by renumbering this i developed this procedure but now we have a similar issue on a SQLite-db.

delete from Ticket
where exists
(select rowid from Ticket t2
where t2.ID = Ticket.ID and t2.rowid < Ticket.rowid)
rowid is the always-present SQLite btree index column.
Thanks to Martin Engelschalk on the SQLite mailing list on 2009-08-17.

Related

SQLite recursive CTE UPDATE working in 3.18.0, SQL_CONSTRAINT in 3.19.0

We have a SQLite CTE UPDATE that was working in versions up to and including 3.18.0, but began failing in 3.19.0 with a FOREIGN KEY constraint (error 19).
The following is a sample toy database that shows the behavior.
sqlite> .version
SQLite 3.18.0 2017-03-28 18:48:43 424a0d380332858ee55bdebc4af3789f74e70a2b3ba1cf29d84b9b4bcf3e2e37
sqlite> .dump t2
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE T2 (Id INTEGER PRIMARY KEY AUTOINCREMENT , ParentId INTEGER NOT NULL , Name TEXT NOT NULL , FavoriteState INT NOT NULL DEFAULT 0, FOREIGN KEY (ParentId) REFERENCES T2(Id) );
INSERT INTO T2 VALUES(1,0,'/',2);
CREATE INDEX idx_pid_t2 ON T2 (ParentId);
CREATE INDEX idx_files_favstate_t2 on T2 (FavoriteState);
CREATE UNIQUE INDEX idx_pnc_t2 ON T2 (ParentId, Name);
COMMIT;
sqlite> PRAGMA foreign_keys=ON;
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 1
WHERE Id IN under_favorite_path;
sqlite> select * from t2;
1|0|/|1
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 2
WHERE Id IN under_favorite_path;
sqlite> select * from t2;
1|0|/|2
Disabling foreign keys in 3.19.0 allows the UPDATE to succeed.
sqlite> .version
SQLite 3.19.0 2017-05-22 13:58:13 28a94eb282822cad1d1420f2dad6bf65e4b8b9062eda4a0b9ee8270b2c608e40
sqlite> .dump t2
PRAGMA foreign_keys=OFF;
BEGIN TRANSACTION;
CREATE TABLE T2 (Id INTEGER PRIMARY KEY AUTOINCREMENT , ParentId INTEGER NOT NULL , Name TEXT NOT NULL , FavoriteState INT NOT NULL DEFAULT 0, FOREIGN KEY (ParentId) REFERENCES T2(Id) );
INSERT INTO T2 VALUES(1,0,'/',2);
CREATE INDEX idx_pid_t2 ON T2 (ParentId);
CREATE INDEX idx_files_favstate_t2 on T2 (FavoriteState);
CREATE UNIQUE INDEX idx_pnc_t2 ON T2 (ParentId, Name);
COMMIT;
sqlite> PRAGMA foreign_keys=ON;
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 1
WHERE Id IN under_favorite_path;
Error: FOREIGN KEY constraint failed
sqlite> PRAGMA foreign_keys=OFF;
sqlite> WITH RECURSIVE under_favorite_path(parent) AS ( VALUES(1) UNION ALL SELECT T2.Id FROM T2 JOIN under_favorite_path ON T2.ParentId = under_favorite_path.parent ) UPDATE T2 SET FavoriteState = 1
WHERE Id IN under_favorite_path;
sqlite> select * from t2;
1|0|/|1
Is this an issue with our CTE that should've been flagged previously or is this something that might've regressed in later SQLite versions?
The problem is not with the CTE, but that the table contains invalid data (0 is not a valid ID):
sqlite> pragma foreign_key_check;
table rowid parent fkid
---------- ---------- ---------- ----------
T2 1 T2 0
When the row gets modified in any way, the constraint is checked:
sqlite> update t2 set name = name;
Error: FOREIGN KEY constraint failed
Apparently, the old version did not check the constraint when the FK column was not modified.

oracle 11 :want to pass cursor variable to variable defined in procedure

Previously i used a temp table which created outside the procedure and inserted data in SP and used,,,but if i want to create a temp table inside procedure it throwing some errors..to avoid that trying to using cursor..
CREATE OR REPLACE PROCEDURE P_EMAIL_update
AS
I NUMBER := 1;
J NUMBER := 0;
ID NUMBER;
BEGIN
INSERT INTO ENTITY_TEMP --(RN,ENTITY_ID)
SELECT ROWNUM, e.id
FROM entity e, company c
WHERE e.companyid = c.id AND e.status = 3;
SELECT MAX (rn) INTO j FROM ENTITY_TEMP;
WHILE i <= j
LOOP
SELECT entity_id
INTO id
FROM ENTITY_TEMP
WHERE rn = i;
INSERT INTO ACTIONS_EMAIL_MAPPING (ID,
ISACTIVE,
ACTIONNAME,
EMAILFROM,
EMAILSUBJECT,
EMAILBODY
)
(SELECT SEQ_ENT.NEXTVAL,
'N',
ACTIONNAME,
EMAILFROM,
EMAILSUBJECT,
EMAILBODY || var_id
FROM ACTIONS
WHERE ISACTIVE = 'T' AND ACTIONNAME NOT IN ('sample'));
I := I + 1;
END LOOP;
END;
The procedure in your question could be rewritten more simply as:
CREATE OR REPLACE PROCEDURE p_email_update AS
BEGIN
INSERT INTO actions_email_mapping (id, isactive, actionname, emailfrom, emailsubject, emailbody)
SELECT seq_ent.nextval,
'N',
a.actionname,
a.emailfrom,
a.emailsubject,
a.emailbody || ent.id -- assuming var_id is a column of actions
FROM actions a
CROSS JOIN (SELECT e.id
FROM entity e
inner join company c on e.companyid = c.id
WHERE e.status = 3) ent -- maybe this should be an inner join with some join conditions?
WHERE a.isactive = 'T'
AND a.actionname NOT IN ('sample');
END p_email_update;
/
There is no need to reinvent a cross join (which is what your code was doing, in a very roundabout way). There is also no need to store the data in a temp table either, based on what you've told us in your question, since you can just reference the subquery directly in the insert-as-select.
I would question why there aren't any join conditions between your actions table, and the subquery on the entity and company tables, though.

Conversion failed when converting the varchar value '/DirectoryName/SubDirectoryName' to data type int

I have a stored procedure that I am calling from an ASP.NET page to get a list of files and some related fields. It fails when the dataset is filled and I am getting an error saying the conversion failed when converting the varchar value to data type int. The field is is referring to is a varchar with relative directory paths. I don't really have a clue why this is happening. An explanation and a solution for this problem would be greatly appreciated. My stored procedure is below.
ALTER proc [dbo].[spFileDownload]
(
#Folder varchar(1000) = null,
#Keyword varchar(1000) = null,
#BatchID IntegerListTable readonly,
#OrgID IntegerListTable readonly
)
as
if #Keyword is not null
begin
Select fldFileName,
fldRelativePathName,
fldDescription,
fldDateAdded,
fldKeywords,
fldBatchDescription
from tblReport
inner join tblBatchLog
on tblBatchLog.fldBatchID = tblReport.fldBatchID
where fldRelativePathName =ISNULL(#Folder, fldRelativePathName)
and Freetext(fldKeywords, #Keyword)
and tblreport.fldBatchID in (Select n from #BatchID)
and fldMembershipID in (select n from #OrgID)
end
else
begin
select fldFileName,
fldRelativePathName,
fldDescription,
fldDateAdded,
fldKeywords,
fldBatchDescription
from tblReport
inner join tblBatchLog
on tblBatchLog.fldBatchID = tblReport.fldBatchID
where fldRelativePathName =ISNULL(#Folder, fldRelativePathName)
and fldRelativePathName in (select n from #BatchID)
and fldMembershipID in (select n from #OrgID)
end
Edit: I failed at reading. Sorry.
and fldRelativePathName in (select n from #BatchID) aren't you comparing a string fldRelativePathName to ints ?
Look at this line...
and fldRelativePathName in (select n from #BatchID)
Column "n" is an integer so SQL is trying to coerce fldRelativePathName

Stored Procedure Where Clause Parameters

I've got an ASP.net search page where the user can enter one or more search criteria. The page calls a stored procedure to query a MS SQL Server 2008 db.
Part of the search criteria is single date or date range. If the user supplies Date1, we search on a single date. If the user supplies Date1 and Date2, we search on a date range.
My issue is coding this logic in the stored proc.
#Date1 datetime
#Date2 datetime
..other search params...
So there are three conditions:
Both #Date1 and #Date2 are null (the user is not searching on dates)
#Date1 is not null and #Date2 is null (the user is searching on a single date)
#Date1 is not null and #Date2 is not null (user is searching a date range)
I can't figure out how to structure the WHERE clause to handle each of the three possible conditions.
I'm familiar with ISNULL() and COALESCE()
Any tips or suggestions are greatly appreciated.
CREATE PROCEDURE BLABLABLA(
#DATE1 DATETIME = NULL,
#DATE2 DATETIME = NULL
)
AS
BEGIN
SELECT COL1, COL2
FROM THE_TABLE
WHERE
THE_TABLE.DATETIMEFIELD BETWEEN
ISNULL(#DATE1, THE_TABLE.DATETIMEFIELD)
AND COALESCE(#DATE2, #DATE1, THE_TABLE.DATETIMEFIELD)
END
Another choice, losing some expressiveness but likely using indexes, could be:
CREATE PROCEDURE BLABLABLA(
#DATE1 DATETIME = NULL,
#DATE2 DATETIME = NULL
)
AS
BEGIN
SELECT COL1, COL2
FROM THE_TABLE
WHERE
(THE_TABLE.DATETIMEFIELD >= #DATE1 OR #DATE1 IS NULL)
AND (THE_TABLE.DATETIMEFIELD <= #DATE2
OR THE_TABLE.DATETIMEFIELD = #DATE1
OR (#DATE1 IS NULL AND #DATE2 IS NULL))
END
You could try to create your SQL query as a string in the SP and then execute it, like this:
...
declare #sql varchar(500)
set #sql = 'select from myTable where 1=1'
if(#Date1 <> null)
set #sql = #sql + ' and date1 >= '+ #date1
if(#Date2 <> null)
set #sql = #sql + ' and date2 <= '+ #date2
print(#sql) -- for debug
exec(#sql)

Stored proc in .net dataset class vs studio management

Morning all. Got myself a simple query which returns ten rows in SQL Server Management Studio. I call the stored proc by right clicking it and feeding in the parameters.
The results are returned immediately.
In .NET we have set up a dataset class, added a table adapter whose select is this same procedure. I pass in the very same parameters and the execution times out after the standard 30 seconds. It continues to run immediately when called in sql server management studio.
Any ideas why the execution time is seemingly infinite in the .net dataset class.
The query is very simple.
ALTER PROCEDURE [dbo].[usp_GetPostcodeAnalysis]
-- Add the parameters for the stored procedure here
#startDate DATETIME,
#endDate DATETIME,
#customerID INTEGER = NULL,
#siteID INTEGER = -1
AS
DECLARE #itemTypeID INT
SELECT #itemTypeID=ItemTypeID FROM dbo.ItemTypes WHERE ItemTypeName = 'Advert'
DECLARE #SQL NVARCHAR(4000)
BEGIN
SET #SQL = 'SELECT at.ActionTypeName,
COUNT(*) AS "Count"
FROM CustomerSites cs JOIN Items i
ON cs.SiteID = i.SiteID
JOIN Actions a
ON a.ItemID = i.ItemID
JOIN ActionTypes at
ON a.ActionTypeID = at.ActionTypeID
WHERE a.DateAndTime BETWEEN #1 AND #2
AND i.ItemTypeID = #iti
AND at.ActionTypeName IN (''List view'', ''Full view'', ''Email enquiry'', ''Print view'', ''Directions'')'
IF #customerID IS NOT NULL
SET #SQL = #SQL + ' AND i.CustomerID = #c'
IF #siteID > -1
SET #SQL = #SQL + ' AND i.SiteID = #s'
SET #SQL = #SQL + ' GROUP BY
at.ActionTypeName
ORDER BY
at.ActionTypeName'
EXECUTE sp_executesql #SQL,
N'#1 DATETIME, #2 DATETIME, #iti INT, #c INT, #s INT',
#startDate, #endDate, #itemTypeID, #customerID, #siteID

Resources