Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dealing with multiple inserts #24

Closed
saaqibz opened this issue Aug 19, 2014 · 8 comments
Closed

Dealing with multiple inserts #24

saaqibz opened this issue Aug 19, 2014 · 8 comments
Assignees
Milestone

Comments

@saaqibz
Copy link
Contributor

saaqibz commented Aug 19, 2014

Hello, Is there a command like executemany() for dealing with multiple inserts?

@SRombauts SRombauts self-assigned this Aug 19, 2014
@SRombauts
Copy link
Owner

Hi, you can simply exec multiple SQL statements separated by semicolon (;)

@saaqibz
Copy link
Contributor Author

saaqibz commented Aug 20, 2014

Thanks for your quick response. That is what I have been doing in the past but I wanted to see if I could do something more efficiently. I know a lot of other libraries had an executemany that tended to be more efficient. Here's one thing I noticed that I ended up doing. Maybe in the future an execute many can be added that utilizes this.

I ended up creating the prepared statement and reusing the same prepared statement resetting the bindings (I also added the wrapper for clearBindings to clear all existing bindings) and iterating just the bind portion.... Below is the section referencing this technique from the documentation for sqlite.

Thank you again for making this useful library.

3.0 Binding Parameters and Reusing Prepared Statements

In prior discussion, it was assumed that each SQL statement is prepared once, evaluated, then destroyed. However, the SQLite allows the same prepared statement to be evaluated multiple times. This is accomplished using the following routines:

sqlite3_reset()
sqlite3_bind()
After a prepared statement has been evaluated by one or more calls to sqlite3_step(), it can be reset in order to be evaluated again by a call to sqlite3_reset(). Using sqlite3_reset() on an existing prepared statement rather than creating a new prepared statement avoids unnecessary calls to sqlite3_prepare(). In many SQL statements, the time needed to run sqlite3_prepare() equals or exceeds the time needed by sqlite3_step(). So avoiding calls to sqlite3_prepare() can result in a significant performance improvement.

Usually, though, it is not useful to evaluate exactly the same SQL statement more than once. More often, one wants to evaluate similar statements. For example, you might want to evaluate an INSERT statement multiple times though with different values to insert. To accommodate this kind of flexibility, SQLite allows SQL statements to contain parameters which are "bound" to values prior to being evaluated. These values can later be changed and the same prepared statement can be evaluated a second time using the new values.

In SQLite, wherever it is valid to include a string literal, one can use a parameter in one of the following forms:

?
?NNN
:AAA
$AAA
@aaa
In the examples above, NNN is an integer value and AAA is an identifier. A parameter initially has a value of NULL. Prior to calling sqlite3_step() for the first time or immediately after sqlite3_reset(), the application can invoke one of the sqlite3_bind() interfaces to attach values to the parameters. Each call to sqlite3_bind() overrides prior bindings on the same parameter.

An application is allowed to prepare multiple SQL statements in advance and evaluate them as needed. There is no arbitrary limit to the number of outstanding prepared statements.

@SRombauts
Copy link
Owner

Okay, I see what you mean, like the 'executemany()' of the Python binding.

I think this could be handy, but this will be in fact less efficient than doing this by yourself (because you will have to prepare the data into an intermediate dynamically allocated list of arguments).

I reopen this request.

@SRombauts SRombauts reopened this Aug 21, 2014
@SRombauts SRombauts added this to the Post 1.0 milestone Apr 30, 2015
@SRombauts
Copy link
Owner

For future reference, link to the python documentation:

# Larger example that inserts many records at a time
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

@xsacha
Copy link

xsacha commented Jul 28, 2016

If you were to make this function, would it be useful to have a bool option to start transaction and end transaction around the execution?
Right now I have a function myself that does this once per second.

@SRombauts
Copy link
Owner

Hi @xsacha, I am not sure of what you mean, can you give a simple example?

@xsacha
Copy link

xsacha commented Jul 29, 2016

I just mean to have:

db->exec("BEGIN");
query->reset();
for (auto statement: collection)
{
// bind everything in statement
query->bind(..);
}
db->exec("END");

SRombauts pushed a commit that referenced this issue Jun 16, 2019
added the option to use a tuple with values to bind.

use this to implement executeMany as described in #24, so it will be possible to pass multiple tuples
@SRombauts
Copy link
Owner

This as finally been implemented and integrated, thanks to @maxbachmann!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants