Tất cả những câu trả lời này đều tốt nếu bạn thực hiện từng dòng một. Tuy nhiên, câu hỏi ban đầu là nhập một tập lệnh sql sẽ được thực thi bởi một lệnh thực thi db duy nhất và tất cả các giải pháp (như kiểm tra xem liệu cột có ở đó trước thời hạn hay không) sẽ yêu cầu chương trình thực thi phải có kiến thức về bảng nào và cột đang được thay đổi / thêm vào hoặc xử lý trước và phân tích cú pháp tập lệnh đầu vào để xác định thông tin này. Thông thường, bạn sẽ không chạy nó trong thời gian thực hoặc thường xuyên. Vì vậy, ý tưởng bắt một ngoại lệ có thể chấp nhận được và sau đó tiếp tục. Trong đó, vấn đề nằm ở chỗ ... làm thế nào để tiếp tục. May mắn thay, thông báo lỗi cung cấp cho chúng tôi tất cả thông tin cần thiết để thực hiện việc này. Ý tưởng là thực thi sql nếu nó ngoại lệ trên lệnh gọi bảng thay đổi, chúng ta có thể tìm thấy dòng bảng thay đổi trong sql và trả về các dòng còn lại và thực thi cho đến khi thành công hoặc không tìm thấy dòng bảng thay đổi phù hợp nào nữa. Đây là một số mã ví dụ trong đó chúng ta có các tập lệnh sql trong một mảng. Chúng tôi lặp lại mảng thực thi từng tập lệnh. Chúng tôi gọi nó hai lần để nhận được lệnh bảng thay đổi không thành công nhưng chương trình thành công vì chúng tôi xóa lệnh bảng thay đổi khỏi sql và thực hiện lại mã đã cập nhật.
exec /opt/usr8.6.3/bin/tclsh8.6 "$0" ${1+"$@"}
foreach pkg {sqlite3 } {
if { [ catch {package require {*}$pkg } err ] != 0 } {
puts stderr "Unable to find package $pkg\n$err\n ... adjust your auto_path!";
}
}
array set sqlArray {
1 {
CREATE TABLE IF NOT EXISTS Notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
note text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
);
CREATE TABLE IF NOT EXISTS Version (
id INTEGER PRIMARY KEY AUTOINCREMENT,
version text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
);
INSERT INTO Version(version) values('1.0');
}
2 {
CREATE TABLE IF NOT EXISTS Tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
tag text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
);
ALTER TABLE Notes ADD COLUMN dump text;
INSERT INTO Version(version) values('2.0');
}
3 {
ALTER TABLE Version ADD COLUMN sql text;
INSERT INTO Version(version) values('3.0');
}
}
sqlite3 db :memory:
proc createSchema { sqlArray } {
upvar $sqlArray sql
foreach version [lsort -integer [array names sql ] ] {
set cmd $sql($version)
set ok 0
while { !$ok && [string length $cmd ] } {
try {
db eval $cmd
set ok 1 ;
} on error { err backtrace } {
if { [regexp {duplicate column name: ([a-zA-Z0-9])} [string trim $err ] match columnname ] } {
puts "Error: $err ... trying again"
set cmd [removeAlterTable $cmd $columnname ]
} else {
throw DBERROR "$err\n$backtrace"
}
}
}
}
}
proc removeAlterTable { sqltext columnname } {
set mode skip
set result [list]
foreach line [split $sqltext \n ] {
if { [string first "alter table" [string tolower [string trim $line] ] ] >= 0 } {
if { [string first $columnname $line ] } {
set mode add
continue;
}
}
if { $mode eq "add" } {
lappend result $line
}
}
if { $mode eq "skip" } {
puts stderr "Unable to find matching alter table line"
return ""
} elseif { [llength $result ] } {
return [ join $result \n ]
} else {
return ""
}
}
proc printSchema { } {
db eval { select * from sqlite_master } x {
puts "Table: $x(tbl_name)"
puts "$x(sql)"
puts "
}
}
createSchema sqlArray
printSchema
createSchema sqlArray
printSchema
sản lượng dự kiến
Table: Notes
CREATE TABLE Notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
note text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
, dump text)
Table: sqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)
Table: Version
CREATE TABLE Version (
id INTEGER PRIMARY KEY AUTOINCREMENT,
version text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
, sql text)
Table: Tags
CREATE TABLE Tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
tag text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
)
Error: duplicate column name: dump ... trying again
Error: duplicate column name: sql ... trying again
Table: Notes
CREATE TABLE Notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
note text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
, dump text)
Table: sqlite_sequence
CREATE TABLE sqlite_sequence(name,seq)
Table: Version
CREATE TABLE Version (
id INTEGER PRIMARY KEY AUTOINCREMENT,
version text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
, sql text)
Table: Tags
CREATE TABLE Tags (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name text,
tag text,
createdDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) ) ,
updatedDate integer(4) DEFAULT ( cast( strftime('%s', 'now') as int ) )
)
user_version
gì? Tôi cho rằng số không, nhưng sẽ rất tuyệt nếu thấy điều đó được ghi lại.