238

Is it somehow possible to create a stored procedure when using SQLite?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
grady
  • 12,281
  • 28
  • 71
  • 110

7 Answers7

261

SQLite has had to sacrifice other characteristics that some people find useful, such as high concurrency, fine-grained access control, a rich set of built-in functions, stored procedures, esoteric SQL language features, XML and/or Java extensions, tera- or peta-byte scalability, and so forth

Source : Appropriate Uses For SQLite

h3xStream
  • 6,293
  • 2
  • 47
  • 57
  • 8
    You can use the SQLite equivalent of SQL CLR functions to achieve the same goal (http://stackoverflow.com/questions/172735/create-use-user-defined-functions-in-system-data-sqlite). – devinbost Sep 02 '14 at 20:05
  • 1
    @bostIT Thanks for the addition. Ref for System.Data.SQLite http://system.data.sqlite.org/index.html/doc/trunk/www/index.wiki – h3xStream Sep 03 '14 at 14:42
120

Answer: NO

Here's Why ... I think a key reason for having stored procs in a database is that you're executing SP code in the same process as the SQL engine. This makes sense for database engines designed to work as a network connected service but the imperative for SQLite is much less given that it runs as a DLL in your application process rather than in a separate SQL engine process. So it makes more sense to implement all your business logic including what would have been SP code in the host language.

You can however extend SQLite with your own user defined functions in the host language (PHP, Python, Perl, C#, Javascript, Ruby etc). You can then use these custom functions as part of any SQLite select/update/insert/delete. I've done this in C# using DevArt's SQLite to implement password hashing.

Community
  • 1
  • 1
Tony O'Hagan
  • 21,638
  • 3
  • 67
  • 78
  • 23
    To clarify ... I'm not saying that there is NO reason to implement SPs in SQLite - just much less reason than in other DB engines. – Tony O'Hagan Feb 18 '13 at 23:01
  • 5
    The KEY reason for having stored procedures is to prevent against SQL Injection. There are many other reasons however. For example being able to Share the relevant queries by having them embedded in the sqlite file. There is absolutely no difference between a standard query which runs in the context of the SQL Engine, and selecting a SP. They are both RUNNING on the SQL ENGINE. – Dan Sep 11 '15 at 18:34
  • 11
    @Dan Firstly, SP's existed long before SQL injection had even been thought of. Thousands of SQL based apps have been built without them that are safe against this attack. I've also code reviewed insecure SPs that are vulnerable to SQL injection (typically based on dynamic SQL). So no I don't this is a primary reason. There's plenty of other ways to prevent this attack further up the stack. – Tony O'Hagan Sep 13 '15 at 06:24
  • 7
    @Dan Most SQL engines are client/server (NOT SQLite!), For these, performance is a key issue when deciding where to put your business logic. Executing business logic be it query OR interative OR conditional code inside an SP in the SQL engine can (1) improve data retrieval performance, (2) reduce network traffic (3) reduce app layer memory usage (4) cache query execution plans (precompiled SPs). Most app developers prefer to move some their business logic outside the SQL engine (obviously not the queries!). For SQLite this is *less* of an imperative as it does not support client/server. – Tony O'Hagan Sep 13 '15 at 06:56
  • Thanks, Tony. I was wondering why SQLite doesn't have procedures but has builtin functions (https://www.sqlite.org/lang_corefunc.html) ? Is it correct that for client-server RDBMS such as postgresql, both functions and procedures are stored on server side? Since SQLite is serverless, if SQLite doesn't have procedures , then for the same reason, should it not have functions either? – Tim May 07 '18 at 12:55
  • @Tim: Functions are still very useful as they are very natural way to express an idempotent expression within an update or query (e.g. my hashed password example). They are not essential but still very useful – Tony O'Hagan May 08 '18 at 03:58
  • @Tim: Yes client-server RDBMS run functions and stored procedures server side. Most modern app developers prefer to use a higher level language (Java/C#/NodeJS/Ruby/Python etc) to implement their business logic as you can create cleaner object-oriented models. However, performance optimisation requirements will often drive you to use server-side RDBMS code (stored procedures and functions). Since SQLite is not client-server this optimisation imperative is a non-issue. – Tony O'Hagan May 08 '18 at 03:59
  • Thanks. SQLite has triggers. Are triggers procedures? – Tim May 08 '18 at 04:27
  • Yes. But a rather clunky way to do it unless you actually wanted a table trigger. Cleaner to just intercept all table updates via an `updateMyTable()` method in your hosting language - no triggers needed. Again ... triggers make sense when you have client/server (I used one in a [MySQL patch last week](https://stackoverflow.com/questions/24645180/dbupdateconcurrencyexception-using-entity-framework-6-with-mysql/50147396#50147396) ) but IMHO hard to justify when you control all updates to your database tables via your hosting language. – Tony O'Hagan May 08 '18 at 07:02
  • For our Android environment, stored procedures allow our code to remain intact and not require updates when a query needs to change. It also allows for uniformity across devices. – Janin Jun 21 '18 at 18:01
  • 1
    As an "Old-School" DBA, I can tell you that in areas that are tightly controlled, the developers are seldom allowed direct database access. Industries that are governed by rules (such as FDA or Military) must ensure that all database access is by stored procedure only. AND... those stored procedures must be locked down and accessible only to fully trained staff for modification. – frozenjim Jan 01 '19 at 13:56
  • @frozenjim - Not relevant for SQList since its only with client side code (in browsers) or small standalone apps that consequently don't use a centralised database. I've worked on many commercial and a mil project where SPs were correctly deemed to be part of the same version controlled code as everything else. Pre-tested, code reviewed DB migration scripts and release management solve the security issues. – Tony O'Hagan Oct 22 '20 at 07:01
21

Yet, it is possible to fake it using a dedicated table, named for your fake-sp, with an AFTER INSERT trigger. The dedicated table rows contain the parameters for your fake sp, and if it needs to return results you can have a second (poss. temp) table (with name related to the fake-sp) to contain those results. It would require two queries: first to INSERT data into the fake-sp-trigger-table, and the second to SELECT from the fake-sp-results-table, which could be empty, or have a message-field if something went wrong.

slashmais
  • 7,069
  • 9
  • 54
  • 80
21

Chris Wolf made a prototype implementation of SQLite with stored procedures. You can find the details at his blog post: Adding Stored Procedures to SQLite

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
torial
  • 13,085
  • 9
  • 62
  • 89
  • 9
    Article is dead now, but the project is at https://github.com/wolfch/sqlite-3.7.3.p1. The readme file implies that this is not production ready, nor is it for experimentation. It seems like it's more of a proof of concept. – pqsk May 13 '16 at 16:15
  • Just a heads up, the edit from @Laurel used the Web Archives -- so the link is now good again. – torial Dec 23 '22 at 19:54
6

No, but you can :

  • Write long multi-statement scripts
  • Create temporary one-row tables called e.g. Vars to hold variables
  • Create a View over a Recursive CTE to program arbitrary functions in pure SQL queries.

So you can do most things you would normally do with stored procs.

For how to program functions in a SQL View see https://www.cafe-encounter.net/p3300/pretending-that-sqlite-has-stored-procedures-and-functions.

Alternatively you can:

  • Compile short single-page C programs to program arbitrary functions

This is easier and less work than you might think!

A step-by-step guide is at https://www.cafe-encounter.net/p3244/installing-and-using-sqlite-extensions-on-macos-and-maybe-windows-linux-too . This does add some deployment work: you will have to deploy the additional dll/so/dylib files with your application.

Chris F Carroll
  • 11,146
  • 3
  • 53
  • 61
  • 2
    Compiling for a single platform is pretty easy. Compiling for deployment across a wide range of platforms is _not_ easy; you end up buried under fiddly detail that's just a little bit different everywhere. That said, you can make functions in many other languages too, depending on what you're embedding SQLite in. – Donal Fellows May 18 '21 at 16:05
1

I've come across this question myself. I think stored procedures are supported in PHP PDO, but that module is handling it and building normal SQL queries to send to SQLite. So, in PHP, possible to write stored procedures in your code, but no performance gain from using them.

Correct me if I'm wrong, please.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
LorenzoP
  • 19
  • 1
  • 2
  • 1
    This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/32730476) – James Risner Sep 22 '22 at 20:09
1

SQLite does not support it natively. But...

I created Stored Procedures for SQLite

Here is an example procedure:

CREATE PROCEDURE add_new_sale(@products) BEGIN 
 INSERT INTO sales (time) VALUES (datetime('now'));
 SET @sale_id = last_insert_rowid();
 FOREACH @prod_id, @qty, @price IN @products DO 
   INSERT INTO sale_items (sale_id, prod_id, qty, price) VALUES (@sale_id, @prod_id, @qty, @price);
 END LOOP;
 RETURN @sale_id;
END;

And how to call it:

CALL add_new_sale(ARRAY( ARRAY('DJI Avata',1,1168.00), ARRAY('iPhone 14',1,799.90), ARRAY('iWatch',2,249.99) ));
Bernardo Ramos
  • 4,048
  • 30
  • 28