NAME
SQL::Inserter - Fast buffered SQL/DBI inserts
VERSION
Version 0.01
SYNOPSIS
use SQL::Inserter;
my $sql = SQL::Inserter->new(
dbh => $dbh,
table => 'table_name',
cols => [qw/column1 column2.../]?,
buffer => 100? # No. of rows for multi-row insert
);
# Fastest method: pass single or multiple rows of data as an array
$sql->insert(@cols);
# For bulk updates, call insert with no
$sql->insert();
# Alternative, pass a single row as a hash, allows SQL code
# instead of values (pass reference)
$sql->insert({
column1 => $data1,
column2 => \'NOW()',
...
});
DESCRIPTION
SQL::Inserter's main OO interface will let you do DBI inserts as efficiently as possible by managing a multi-row buffer and prepared statements.
You only have to select the number of rows for the buffered writes (default is 100) and choose whether to pass your data in arrays (fastest, requires all data to be bind values, will execute the same prepared statement every time the buffer is full) or hashes (allows SQL code apart from plain values).
It also provides lightweight functions that return the SQL queries to be used manually, similar to SQL::Abstract::insert
, but much faster.
EXPORTS
On request: simple_insert
multi_insert_sql
.
CONSTRUCTOR
new
my $sql = SQL::Inserter->new(
dbh => $dbh,
table => $table,
cols => \@column_names?,
buffer => 100?,
duplicates => $ignore_or_update?,
null_undef => $convert_undef_to_NULL
);
Creates an object to insert data to a specific table. Buffering is enabled by default and anything left on it will be written when the object falls out of scope / is destroyed.
Required parameters:
dbh
: A DBI database handle.table
: The name of the db table to insert to. See "NOTES" if you are using a restricted word for a table name.
Optional parameters:
cols
: The names of the columns to insert. It is required if arrays are used to pass the data. With hashes they are optional (the order will be followed if they are defined). See "NOTES" if you are using any restricted words for column names.buffer
: Max number of rows to be held in buffer before there is a write. The buffer empties (writes contents) when the object is destroyed. Setting it to 1 writes each row separately (least efficient). For small rows you can set buffer to thousands. The default is a (conservative) 100 which works with big data rows.duplicates
: For MySQL, define as'ignore'
or'update'
to get anINSERT IGNORE
orON DUPLICATE KEY UPDATE
query respectively. See "NOTES" for details on the latter.null_undef
: Applies to the hash inserts only. If true, any undefined values will be converted to SQL'sNULL
(similar to theSQL::Abstract
default). The default behaviour will leave an undef as the bind variable, which may either create an empty string in the db or give an error depending on your column type and db settings.
METHODS
insert
# Fastest array method. Only bind data is passed.
$sql->insert(@column_data_array);
# Alternative, allows SQL code as values in addition to bind variables
$sql->insert(\%row_data);
# No parameters will force emtying of buffer (db write)
$sql->insert();
The main insert method. It works in two modes, by passing an array or a hashref:
Array mode
Pass the data for one or more rows in a flat array, buffering will work automatically based on your buffer
settings. Obviously your @column_data_array
has to contain a multiple of the number of cols
defined on the constructor.
This is the fastest mode, but it only allows simple bind values (not even NULL
- undef
s will be directly passed to DBI->execute);
Hash mode
Pass a reference to a hash containing the column names & values for a single row of data. If cols
was not defined on the constructor, the columns from the first data row will be used instead. For subsequent rows any extra columns will be disregarded and any missing columns will be considered to have an undef
(which can be automatically converted to NULL
if the null_undef
option was set).
Emptying buffer
Calling insert
with no arguments forces a write to the db, emptying the buffer. You don't have to call this manually, the same will happen when the object is destroyed.
Mixing modes
You can theoretically mix modes, but only when the buffer is empty e.g. you can start with the array mode, empty the buffer and continue with hash mode (cols
will be defined from the array mode). Or you can start with hash mode (so cols
will be defined from the very first hash), and after emptying the buffer you can switch to array mode.
ATTRIBUTES
last_retval
my $val = $sql->{last_retval}
The return value of the last DBI execute()
is stored in this attribute. On a successful insert it should contain the number of rows of that statement. Note that an insert
call, depending on the buffering, may call execute()
zero, one or more times.
row_total
my $total = $sql->{row_total}
Basically a running total of the return values, for successful inserts it shows you how many rows were inserted into the database. It will be undef if no execute()
has been called.
buffer_counter
my $count = $sql->{buffer_counter}
Check how many un-inserted data rows the buffer currently holds.
FUNCTIONS
simple_insert
# Single row
my ($sql, @bind) = simple_insert($table, \%fieldvals, \%options);
# Multi-row
my ($sql, @bind) = simple_insert($table, [\%fieldvals,...], \%options);
Returns the SQL statement and bind variable array for a hash containing the row columns and values. Values are treated as bind variables unless they are references to SQL code strings. E.g. :
my ($sql, @bind) = simple_insert('table', {foo=>"bar",when=>\"NOW()"});
### INSERT INTO table (foo, when) VALUES (?,NOW())
The function also accepts an array of hashes to allow multi-row inserts:
my ($sql, @bind) = simple_insert('table', [{foo=>"foo"},{foo=>"bar"}]);
### INSERT INTO table (foo) VALUES (?),(?)
The first row (element in array) needs to contain the superset of all the columns that you want to insert, if some of your rows have undefined column data.
Options:
null_undef
: If true, any undefined values will be converted to SQL'sNULL
(similar to theSQL::Abstract
default). The default behaviour will leave an undef as the bind variable, which may either create an empty string in the db or give an error depending on your column type and db settings.duplicates
: For MySQL, define as'ignore'
or'update'
to get anINSERT IGNORE
orON DUPLICATE KEY UPDATE
query respectively. See "NOTES" for details on the latter.
multi_insert_sql
my $sql = multi_insert_sql(
$table,
\@columns, # names of table columns
$num_of_rows?, # default = 1
$duplicates? # can be set as ignore/update in case of duplicate key (MySQL)
);
Builds bulk insert query (single insert is possible too), with ability for ignore/on duplicate key update variants for MySQL.
Requires at least the name of the table $table
and an arrayref with the column names \@columns
. See "NOTES" if you want to quote table or column names.
Optional parameters:
$num_of_rows
: By default it returns SQL with bind value placeholders for a single row. You can define any number of rows to use with multi-row bind variable arrays.$duplicate
: For MySQL, passing'ignore'
as the 4th argument returns anINSERT IGNORE
query. Passing'update'
as the argument returns a query containing an `ON DUPLICATE KEY UPDATE` clause (see "NOTES" for further details).
NOTES
Using reserved words as object names
If you are using reserved words as table/column names (which is strongly discouraged), just include the appropriate delimiter in the table
or cols
parameter. E.g. for MySQL with columns named from
and to
you can do:
cols => [qw/`from` `to`/]
For PostgreSQL or Oracle you'd do [qw/"from" "to"/]
, for SQL Server [qw/[from] [to]/]
etc.
On duplicate key update
The duplicates => 'update'
option creates an ON DUPLICATE KEY UPDATE
clause for the query. E.g.:
my $sql = multi_insert_sql('table_name', [qw/col1 col2/], 2, 'update');
will produce:
## INSERT INTO table_name (col1,col2) VALUES (?,?),(?,?) ON DUPLICATE KEY UPDATE col1=VALUES(col1),col2=VALUES(col2)
Note that as of MySQL 8.0.20 the VALUES
in UPDATE
is deprecated (row alias is used instead), so this functionality might need to be updated some day if VALUES
is removed completely.
AUTHOR
Dimitrios Kechagias, <dkechag at cpan.org>
BUGS
Please report any bugs or feature requests either on GitHub (preferred), or on RT (via the email <bug-sql-inserter at rt.cpan.org>, or https://rt.cpan.org/NoAuth/ReportBug.html?Queue=SQL-Inserter).
I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
GIT
https://github.com/SpareRoom/SQL-Inserter
CPAN
https://metacpan.org/release/SQL-Inserter
LICENSE AND COPYRIGHT
Copyright (C) 2023, SpareRoom.com
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.