为什么自增主键列在sqlite3中不自增
why autoincrement primary key column not autoincrementing in sqlite3
我有一个地址簿的 sqlite3 数据库,我用
创建了地址 table
my $dbcreate = qq(CREATE TABLE IF NOT EXISTS address
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
LASTNAME TEXT NOT NULL,
FIRSTNAME TEXT NOT NULL,
COMPANY TEXT,
STREET TEXT,
CITY TEXT,
STATE TEXT,
COUNTRY TEXT,
ZIPCODE TEXT,
MOBILE TEXT,
OTHERPHONE TEXT,
FAX TEXT,
EMAIL TEXT,
EMAIL2 TEXT,
WEBSITE TEXT,
WEBSITE2 TEXT,
DOB DATE,
NOTES TEXT,
TAGS TEXT););
因此,据我所知,第一列应该是一个自动递增的主 ID,只是它不是自动递增的。我从阅读 sqlite 教程中了解到,我应该只需要输入其他 18 个值,并且该列应该自动递增,但是如果我插入 18 个值,我会被告知我缺少一个。
如果我手动设置 ROWID,我只能插入行。
给出了什么?
这是我添加行的方式(未成功)
#!/usr/bin/perl -w
# script to enter a new addressbook entry
use DBI;
use strict;
use warnings;
print "Please enter a DB username? \n";
my $userid=<STDIN>;
chomp($userid);
print "Please enter a DB password? \n";
my $password=<STDIN>;
chomp($password);
my $driver = "SQLite";
my $database = "myaddress.db";
my $dsn = "DBI:$driver:dbname=$database";
my $dbh = DBI->connect($dsn, $userid, $password, { RaiseError => 1 })
or die $DBI::errstr;
print "Successfull DB connection\n";
print "Creating new address book entry\n";
my $arval = 0;
my @dbits = ('LASTNAME','FIRSTNAME','COMPANY','STREET','CITY','STATE','COUNTRY','ZIPCODE','MOBILE','OTHERPHONE','FAX','EMAIL','EMAIL2','WEBSITE','WEBSITE2','DOB','NOTES','TAGS');
# print "@dbits";
# for $b (0 .. 17) {
# print "\'$dbits[$b]\', ";
# }
print "-----\n";
my @nubits = ();
foreach my $databit(@dbits) {
print "Enter $databit: \n";
my $nubit = <STDIN>;
chomp($nubit);
print "$databit = $nubit\n\n";
push(@nubits,$nubit);
print "$databit = $nubits[$arval]\n";
my $arval = (++$arval);
print "$arval\n";
}
# print "new entry will be:\n";
# for $b (0 .. 17) {
# print "$nubits[$b] | ";
# }
my $entry = qq(INSERT INTO address VALUES('$nubits[0]','$nubits[1]','$nubits[2]','$nubits[3]','$nubits[4]','$nubits[5]','$nubits[6]','$nubits[7]','$nubits[8]','$nubits[9]','$nubits[10]','$nubits[11]','$nubits[12]','$nubits[13]','$nubits[14]','$nubits[15]','$nubits[16]','$nubits[17]'););
my $retval = $dbh->do($entry);
if($retval < 0){
print $DBI::errstr;
} else {
print "entry created successfully\n";
}
my $query = qq(select * from address);
print $query;
$dbh->disconnect();
我可以从 cli 手动使用 sqlite3 输入行,但是,如前所述,我必须手动设置 ROWID/Primary ID。
过去,我只使用带有 tcl/tk 的 sqlite,从不使用 perl,但即使我是一个完整的 perl n00b,我也不认为 perl 是我的问题。 sqlite3 没有按预期运行(除非我完全误读了十几个教程,这些教程指出设置为自动增量的主键 id 应该是自动增量)。
尝试像这样在插入中使用 null:
my $entry = qq(INSERT INTO address VALUES(null,'$nubits[0]','$nubits[1]',...
它不会自动递增,因为你已经给了它一个 id,$nubits[0]
。
没有列列表,INSERT INTO address VALUES (...)
插入 table 中的所有列。您 ,但这只是隐藏了该查询的另一个问题。
INSERT INTO address VALUES (...)
需要知道 address
的创建顺序才能知道元素 5 是街道。如果有任何更改 table 中的顺序,您的 INSERT 就会中断。如果添加了一列,您的查询就会中断。如果您将值放在错误的位置(就像您所做的那样),则很难分辨。使用显式列列表会更好。
INSERT INTO address
(lastname, firstname, company, street, ...)
VALUES
(...)
现在您的 ID 将递增 并且 您可以免受将来 table 更改的影响。如果这看起来工作量很大,请将其设为一个函数,该函数采用散列值来构建查询。它比记住 $nubits[12]
是什么更具可读性。但在你这样做之前,看看 DBIx::Class 已经为你做了这件事。
不提bind parameters. These are faster, allowing you to use prepared statements, and they protect you against SQL injection attacks是我的失职。
如前所述,问题是 INSERT
的 VALUES
部分中的项目被一对一分配给 table 中的列它们首先被创建的顺序。如果您只需要为列的子集提供值,那么您还需要提供应接收值的列名列表。
如果没有列名,值将按照列的创建顺序分配给列,因此末尾的列将不会收到值。在这种情况下,数据库会将 LASTNAME
列的值分配给 ID
,最后的 TAGS
元素没有值。
在 SQL 语句中使用 placeholders 也更好,并使用 prepare
和 execute
而不是只是 do
。这样 DBI
模块将根据它们的数据类型适当地引用和转义实际值。
这个程序展示了如何做到这一点
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use DBD::SQLite;
STDOUT->autoflush;
my ($driver, $dbname) = qw/ SQLite myaddress.db /;
my $dsn = "DBI:$driver:dbname=$dbname";
print 'Please enter a DB username: ';
my $username = <STDIN>;
chomp($username);
print 'Please enter a DB password: ';
my $password = <STDIN>;
chomp($password);
my $dbh = DBI->connect($dsn, $username, $password, { RaiseError => 1 });
print "Successful DB connection\n";
print "Creating new address book entry...\n";
print "-----\n";
my @dbits = qw/
LASTNAME FIRSTNAME COMPANY STREET
CITY STATE COUNTRY ZIPCODE
MOBILE OTHERPHONE FAX EMAIL
EMAIL2 WEBSITE WEBSITE2 DOB
NOTES TAGS
/;
my @nubits;
for my $databit (@dbits) {
print "Enter $databit: ";
my $nubit = <STDIN>;
chomp($nubit);
push @nubits, $nubit;
print "$databit = $nubits[-1]\n";
print scalar @nubits, "\n";
}
my $columns = join ', ', @dbits;
my $placeholders = join ', ', ('?') x @dbits;
my $insert = <<"__END__SQL__";
INSERT INTO address (
$columns
)
VALUES (
$placeholders
)
__END__SQL__
$insert = $dbh->prepare($insert);
$insert->execute(@nubits);
print "Entry created successfully\n";
$dbh->disconnect;
这会在 $insert
中创建一个 SQL 语句,如下所示
INSERT INTO address (
LASTNAME, FIRSTNAME, COMPANY, STREET, CITY, STATE, COUNTRY, ZIPCODE, MOBILE, OTHERPHONE, FAX, EMAIL, EMAIL2, WEBSITE, WEBSITE2, DOB, NOTES, TAGS
)
VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
我有一个地址簿的 sqlite3 数据库,我用
创建了地址 table my $dbcreate = qq(CREATE TABLE IF NOT EXISTS address
(ID INTEGER PRIMARY KEY AUTOINCREMENT,
LASTNAME TEXT NOT NULL,
FIRSTNAME TEXT NOT NULL,
COMPANY TEXT,
STREET TEXT,
CITY TEXT,
STATE TEXT,
COUNTRY TEXT,
ZIPCODE TEXT,
MOBILE TEXT,
OTHERPHONE TEXT,
FAX TEXT,
EMAIL TEXT,
EMAIL2 TEXT,
WEBSITE TEXT,
WEBSITE2 TEXT,
DOB DATE,
NOTES TEXT,
TAGS TEXT););
因此,据我所知,第一列应该是一个自动递增的主 ID,只是它不是自动递增的。我从阅读 sqlite 教程中了解到,我应该只需要输入其他 18 个值,并且该列应该自动递增,但是如果我插入 18 个值,我会被告知我缺少一个。 如果我手动设置 ROWID,我只能插入行。 给出了什么?
这是我添加行的方式(未成功)
#!/usr/bin/perl -w
# script to enter a new addressbook entry
use DBI;
use strict;
use warnings;
print "Please enter a DB username? \n";
my $userid=<STDIN>;
chomp($userid);
print "Please enter a DB password? \n";
my $password=<STDIN>;
chomp($password);
my $driver = "SQLite";
my $database = "myaddress.db";
my $dsn = "DBI:$driver:dbname=$database";
my $dbh = DBI->connect($dsn, $userid, $password, { RaiseError => 1 })
or die $DBI::errstr;
print "Successfull DB connection\n";
print "Creating new address book entry\n";
my $arval = 0;
my @dbits = ('LASTNAME','FIRSTNAME','COMPANY','STREET','CITY','STATE','COUNTRY','ZIPCODE','MOBILE','OTHERPHONE','FAX','EMAIL','EMAIL2','WEBSITE','WEBSITE2','DOB','NOTES','TAGS');
# print "@dbits";
# for $b (0 .. 17) {
# print "\'$dbits[$b]\', ";
# }
print "-----\n";
my @nubits = ();
foreach my $databit(@dbits) {
print "Enter $databit: \n";
my $nubit = <STDIN>;
chomp($nubit);
print "$databit = $nubit\n\n";
push(@nubits,$nubit);
print "$databit = $nubits[$arval]\n";
my $arval = (++$arval);
print "$arval\n";
}
# print "new entry will be:\n";
# for $b (0 .. 17) {
# print "$nubits[$b] | ";
# }
my $entry = qq(INSERT INTO address VALUES('$nubits[0]','$nubits[1]','$nubits[2]','$nubits[3]','$nubits[4]','$nubits[5]','$nubits[6]','$nubits[7]','$nubits[8]','$nubits[9]','$nubits[10]','$nubits[11]','$nubits[12]','$nubits[13]','$nubits[14]','$nubits[15]','$nubits[16]','$nubits[17]'););
my $retval = $dbh->do($entry);
if($retval < 0){
print $DBI::errstr;
} else {
print "entry created successfully\n";
}
my $query = qq(select * from address);
print $query;
$dbh->disconnect();
我可以从 cli 手动使用 sqlite3 输入行,但是,如前所述,我必须手动设置 ROWID/Primary ID。
过去,我只使用带有 tcl/tk 的 sqlite,从不使用 perl,但即使我是一个完整的 perl n00b,我也不认为 perl 是我的问题。 sqlite3 没有按预期运行(除非我完全误读了十几个教程,这些教程指出设置为自动增量的主键 id 应该是自动增量)。
尝试像这样在插入中使用 null:
my $entry = qq(INSERT INTO address VALUES(null,'$nubits[0]','$nubits[1]',...
它不会自动递增,因为你已经给了它一个 id,$nubits[0]
。
没有列列表,INSERT INTO address VALUES (...)
插入 table 中的所有列。您
INSERT INTO address VALUES (...)
需要知道 address
的创建顺序才能知道元素 5 是街道。如果有任何更改 table 中的顺序,您的 INSERT 就会中断。如果添加了一列,您的查询就会中断。如果您将值放在错误的位置(就像您所做的那样),则很难分辨。使用显式列列表会更好。
INSERT INTO address
(lastname, firstname, company, street, ...)
VALUES
(...)
现在您的 ID 将递增 并且 您可以免受将来 table 更改的影响。如果这看起来工作量很大,请将其设为一个函数,该函数采用散列值来构建查询。它比记住 $nubits[12]
是什么更具可读性。但在你这样做之前,看看 DBIx::Class 已经为你做了这件事。
不提bind parameters. These are faster, allowing you to use prepared statements, and they protect you against SQL injection attacks是我的失职。
如前所述,问题是 INSERT
的 VALUES
部分中的项目被一对一分配给 table 中的列它们首先被创建的顺序。如果您只需要为列的子集提供值,那么您还需要提供应接收值的列名列表。
如果没有列名,值将按照列的创建顺序分配给列,因此末尾的列将不会收到值。在这种情况下,数据库会将 LASTNAME
列的值分配给 ID
,最后的 TAGS
元素没有值。
在 SQL 语句中使用 placeholders 也更好,并使用 prepare
和 execute
而不是只是 do
。这样 DBI
模块将根据它们的数据类型适当地引用和转义实际值。
这个程序展示了如何做到这一点
#!/usr/bin/perl
use strict;
use warnings;
use DBI;
use DBD::SQLite;
STDOUT->autoflush;
my ($driver, $dbname) = qw/ SQLite myaddress.db /;
my $dsn = "DBI:$driver:dbname=$dbname";
print 'Please enter a DB username: ';
my $username = <STDIN>;
chomp($username);
print 'Please enter a DB password: ';
my $password = <STDIN>;
chomp($password);
my $dbh = DBI->connect($dsn, $username, $password, { RaiseError => 1 });
print "Successful DB connection\n";
print "Creating new address book entry...\n";
print "-----\n";
my @dbits = qw/
LASTNAME FIRSTNAME COMPANY STREET
CITY STATE COUNTRY ZIPCODE
MOBILE OTHERPHONE FAX EMAIL
EMAIL2 WEBSITE WEBSITE2 DOB
NOTES TAGS
/;
my @nubits;
for my $databit (@dbits) {
print "Enter $databit: ";
my $nubit = <STDIN>;
chomp($nubit);
push @nubits, $nubit;
print "$databit = $nubits[-1]\n";
print scalar @nubits, "\n";
}
my $columns = join ', ', @dbits;
my $placeholders = join ', ', ('?') x @dbits;
my $insert = <<"__END__SQL__";
INSERT INTO address (
$columns
)
VALUES (
$placeholders
)
__END__SQL__
$insert = $dbh->prepare($insert);
$insert->execute(@nubits);
print "Entry created successfully\n";
$dbh->disconnect;
这会在 $insert
中创建一个 SQL 语句,如下所示
INSERT INTO address (
LASTNAME, FIRSTNAME, COMPANY, STREET, CITY, STATE, COUNTRY, ZIPCODE, MOBILE, OTHERPHONE, FAX, EMAIL, EMAIL2, WEBSITE, WEBSITE2, DOB, NOTES, TAGS
)
VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)