目前我正在运行
SQLiteDatabase db = DB_Helper.getWritableCustom();
db.rawQuery("select 'insert into tasks_ordered values' || group_concat(a,',') || ';' as b from (\n" +
"select '(' ||\n" +
"\n" +
"CASE typeof(_id) WHEN 'text' THEN \"'\" || REPLACE(_id,\"'\",\"''\") || \"'\" WHEN 'null' THEN 'null' WHEN 'blob' THEN 'blob??' ELSE _id END\n" +
" ||','|| CASE typeof(_task_id) WHEN 'text' THEN \"'\" || REPLACE(_task_id,\"'\",\"''\") || \"'\" WHEN 'null' THEN 'null' WHEN 'blob' THEN 'blob??' ELSE _task_id END\n" +
" ||','|| CASE typeof(type) WHEN 'text' THEN \"'\" || REPLACE(type,\"'\",\"''\") || \"'\" WHEN 'null' THEN 'null' WHEN 'blob' THEN 'blob??' ELSE type END\n" +
" \n" +
"|| ')' as a from tasks_ordered \n" +
")",null);
cursor.moveToFirst();
String inserts = cursor.getString(0);
cursor.close();
这里是没有java转义字符的查询:
select 'insert into tasks_ordered values' || group_concat(a,',') || ';' as b from (
select '(' ||
CASE typeof(_id) WHEN 'text' THEN "'" || REPLACE(_id,"'","''") || "'" WHEN 'null' THEN 'null' WHEN 'blob' THEN 'blob??' ELSE _id END
||','|| CASE typeof(_task_id) WHEN 'text' THEN "'" || REPLACE(_task_id,"'","''") || "'" WHEN 'null' THEN 'null' WHEN 'blob' THEN 'blob??' ELSE _task_id END
||','|| CASE typeof(type) WHEN 'text' THEN "'" || REPLACE(type,"'","''") || "'" WHEN 'null' THEN 'null' WHEN 'blob' THEN 'blob??' ELSE type END
|| ')' as a from tasks_ordered
);
查询输出示例:
insert into tasks_ordered values(0,null,10),(1,null,11),(2,591,0),(3,603,0),(4,627,0),(5,null,12),(6,639,0),(8,675,1),(9,699,1),(10,711,1);
但它只是感觉有点矫枉过正。是否有一种我可以直接使用的sys方法,而不是每次都重新发明轮子?
答案 0 :(得分:0)
没有内置方法。
sqlite3
shell使用等效代码实现相同的输出(.mode insert
)。
答案 1 :(得分:0)
我个人会复制整个数据库文件,但这确实假设使用SQLite兼容的应用程序。
但是,另一种方法是拥有自己的通用方法。以下是一个示例(未完全测试,因此可能需要浮点数,blob和转义字符串的工作): -
public static String getTableInsertStatements(SQLiteDatabase db, String table) {
if (table.length() < 1) {
return "";
}
StringBuilder values = new StringBuilder();
//String values = "";
Cursor csr = getAllRowsFromTable(db,table,true,null);
long rowcount = csr.getCount();
while (csr.moveToNext()) {
for (int i=0; i < csr.getColumnCount(); i++) {
if (i==0) {
values.append(" (");
}
switch (csr.getType(i)) {
case Cursor.FIELD_TYPE_NULL:
values.append("null");
break;
case Cursor.FIELD_TYPE_INTEGER:
values.append(Long.toString(csr.getLong(i)));
break;
case Cursor.FIELD_TYPE_FLOAT:
values.append(Double.toString(csr.getDouble(i)));
break;
case Cursor.FIELD_TYPE_STRING:
String unescaped_string = csr.getString(i);
// NEED TO HANDLE ESCAPING HERE
//values.append("'" + unescaped_string + "'");
// Limited ESCAPING
values.append("'" + unescaped_string.replace("'","''") + "'");
break;
case Cursor.FIELD_TYPE_BLOB:
values.append("X'" + getBytedata(csr.getBlob(i),2147483647) + "'");
break;
}
// Add comma separator between values in current column unless last column
if (i < (csr.getColumnCount() - 1)) {
values.append(",");
}
// Add closing parenthesis after the last value of the row
if (i == csr.getColumnCount() - 1) {
values.append(")");
}
}
if (!csr.isLast()) {
values.append(",");
}
}
if (values.length() > 1 ) {
return "INSERT INTO " + table + " VALUES " + values.toString() + ";";
}
return "";
}
以上使用其他常用实用程序,因此权利类(CommonSQLiteutilities)为: -
public class CommonSQLiteUtilities {
public static final boolean ERROR_CHECKING_ON = true;
public static final boolean ERROR_CHECKING_OFF = false;
// SQLite MASTER TABLE definitions
static final String SQLITE_MASTER = "sqlite_master";
static final String SM_TABLE_TYPE_COLUMN = "type";
static final String SM_NAME_COLUMN = "name";
static final String SM_TABLENAME_COLUMN = "tbl_name";
static final String SM_ROOTPAGE_COLUMN = "rootpage";
static final String SM_SQL_COLUMN = "sql";
static final String SM_TYPE_TABLE = "table";
static final String SM_TYPE_INDEX = "index";
static final String PRAGMA_STATEMENT = "PRAGMA ";
static final String PRAGMA_DATABASELIST = "database_list";
static final String PRAGMA_USERVERSION = "user_version";
static final String PRAGMA_ENCODING = "encoding";
static final String PRAGMA_FOREIGNKEYLIST = "foreign_key_list";
static final String PRAGMA_INDEXINFO = "index_info";
static final String PRAGMA_INDEXLIST = "index_list";
static final String PRAGMA_TABLEINFO = "table_info";
static final String PRAGMA_DBLIST_SEQ_COL = "seq";
static final String PRAGMA_DBLIST_NAME_COL = "name";
static final String PRAGMA_DBLIST_FILE_COL = "file";
static final String PRAGMA_TABLEINFO_CID_COL = "cid";
static final String PRAGMA_TABLEINFO_NAME_COl = "name";
static final String PRAGMA_TABLEINFO_TYPE_COL = "type";
static final String PRAGMA_TABLEINFO_NOTNULL_COL = "notnull";
static final String PRAGMA_TABLEINFO_DEFAULTVALUE_COL = "dflt_value";
static final String PRAGMA_TABLEINFO_PRIMARYKEY_COL = "pk";
static final String CSU_TAG = "SQLITE_CSU";
private CommonSQLiteUtilities() {}
/**
* Write Database information to the log;
* Information wrttien is:
* the database path, (will/should show connected databases)
* the version number (note! user version i.e. version coded in DBHelper),
* the tables in the database (includes android_metadata but not sqlite_master),
* the columns of the tables
* @param db The SQLite database to be interrogated
*/
public static void logDatabaseInfo(SQLiteDatabase db) {
// Issue PRAGMA database_list commnand
Cursor dblcsr = db.rawQuery(PRAGMA_STATEMENT + PRAGMA_DATABASELIST,null);
// Write databases to the log
while (dblcsr.moveToNext()) {
Log.d(CSU_TAG,"DatabaseList Row " + Integer.toString(dblcsr.getPosition() + 1) +
" Name=" + dblcsr.getString(dblcsr.getColumnIndex(PRAGMA_DBLIST_NAME_COL)) +
" File=" + dblcsr.getString(dblcsr.getColumnIndex(PRAGMA_DBLIST_FILE_COL))
);
}
dblcsr.close();
// Issue PRAGMA user_version to get the version and write to the log
//Note! to set user_version use execSQL not rawQuery
Cursor uvcsr = db.rawQuery(PRAGMA_STATEMENT + PRAGMA_USERVERSION,null);
while (uvcsr.moveToNext()) {
Log.d(CSU_TAG,"Database Version = " +
Integer.toString(uvcsr.getInt(uvcsr.getColumnIndex(PRAGMA_USERVERSION))));
}
uvcsr.close();
// Select all table entry rows from sqlite_master
Cursor tlcsr = db.rawQuery("SELECT * FROM " +
SQLITE_MASTER + " WHERE " +
SM_TABLE_TYPE_COLUMN + "='" + SM_TYPE_TABLE + "'"
,null);
// For each table write table information to the log
// (inner loop gets column info per table)
while (tlcsr.moveToNext()) {
String current_table = tlcsr.getString(tlcsr.getColumnIndex(SM_TABLENAME_COLUMN));
Log.d(CSU_TAG,
"Table Name = " + current_table +
" Created Using = " + tlcsr.getString(tlcsr.getColumnIndex(SM_SQL_COLUMN)),
null
);
// Issue PRAGMA tabel_info for the current table
Cursor ticsr = db.rawQuery(PRAGMA_STATEMENT + PRAGMA_TABLEINFO +
"(" + current_table + ")",
null
);
// Write column info (see headings below) to the log
while (ticsr.moveToNext()) {
Log.d(CSU_TAG,"Table = " +
current_table +
" ColumnName = " +
ticsr.getString(ticsr.getColumnIndex(PRAGMA_TABLEINFO_NAME_COl)) +
" ColumnType = " +
ticsr.getString(ticsr.getColumnIndex(PRAGMA_TABLEINFO_TYPE_COL)) +
" Default Value = " +
ticsr.getString(ticsr.getColumnIndex(PRAGMA_TABLEINFO_DEFAULTVALUE_COL)) +
" PRIMARY KEY SEQUENCE = " + Integer.toString(
ticsr.getInt(ticsr.getColumnIndex(PRAGMA_TABLEINFO_PRIMARYKEY_COL))
)
);
}
ticsr.close();
}
tlcsr.close();
}
/**
* Generic get all rows from an SQlite table,
* allowing the existence of the table to be checked and also
* allowing the ROWID to be added AS a supplied string
*
* @param db The SQLiteDatabase
* @param tablename The name of the table from which the
* returned cursor will be created from;
* Note!
* @param use_error_checking Whether ot not to try to detect errors
* currently just table doesn't exist,
* true to turn on, false to turn off
* ERROR_CHECKING_ON = true
* ERROR_CHECKING_OFF = false
* @param forceRowidAs If length of string passed is 1 or greater
* then a column, as an alias of ROWID, will be
* added to the cursor
* @return the extracted cursor, or in the case of the
* underlying table not existing an empty cursor
* with no columns
*/
public static Cursor getAllRowsFromTable(SQLiteDatabase db,
String tablename,
boolean use_error_checking,
String forceRowidAs) {
String[] columns = null;
// Tablename must be at least 1 character in length
if (tablename.length() < 1) {
Log.d(CSU_TAG,new Object(){}.getClass().getEnclosingMethod().getName() +
" is finishing as the provided tablename is less than 1 character in length"
);
return new MatrixCursor(new String[]{});
}
// If use_error_checking is true then check that the table exists
// in the sqlite_master table
if (use_error_checking) {
Cursor chkcsr = db.query(SQLITE_MASTER,null,
SM_TABLE_TYPE_COLUMN + "=? AND "
+ SM_TABLENAME_COLUMN + "=?",
new String[]{SM_TYPE_TABLE,tablename},
null,null,null
);
// Ooops table is not in the Database so return an empty
// column-less cursor
if (chkcsr.getCount() < 1) {
Log.d(CSU_TAG,"Table " + tablename +
" was not located in the SQLite Database Master Table."
);
// return empty cursor with no columns
return new MatrixCursor(new String[]{});
}
chkcsr.close();
}
// If forcing an alias of ROWID then user ROWID AS ???, *
if(forceRowidAs != null && forceRowidAs.length() > 0) {
columns = new String[]{"rowid AS " +forceRowidAs,"*"};
}
// Finally return the Cursor but trap any exceptions
try {
return db.query(tablename, columns, null, null, null, null, null);
} catch (Exception e) {
Log.d(CSU_TAG,"Exception encountered but trapped when querying table " + tablename +
" Message was: \n" + e.getMessage());
Log.d(CSU_TAG,"Stacktrace was:");
e.printStackTrace();
return new MatrixCursor(new String[]{});
}
}
/**
* Create and return a Cursor devoid of any rows and columns
* Not used, prehaps of very little use.
* @param db The Sqlite database in which the cursor is to be created
* @return The empty Cursor
*/
private static Cursor getEmptyColumnLessCursor(SQLiteDatabase db) {
return new MatrixCursor(new String[]{});
}
/**
* Write column names in the passed Cursor to the log
* @param csr The Cursor to be inspected.
*/
public static void logCursorColumns(Cursor csr) {
Log.d(CSU_TAG,
new Object(){}.getClass().getEnclosingMethod().getName() +
" invoked. Cursor has the following " +
Integer.toString(csr.getColumnCount())+
" columns.");
int position = 0;
for (String column: csr.getColumnNames()) {
position++;
Log.d(CSU_TAG,"Column Name " +
Integer.toString(position) +
" is "
+ column
);
}
}
/**
* Write the contents of the Cursor to the log
* @param csr The Cursor that is to be displayed in the log
*/
public static void logCursorData(Cursor csr) {
int columncount = csr.getColumnCount();
int rowcount = csr.getCount();
int csrpos = csr.getPosition(); //<<< added 20171016
Log.d(CSU_TAG,
new Object(){}.getClass().getEnclosingMethod().getName() +
" Cursor has " +
Integer.toString(rowcount) +
" rows with " +
Integer.toString(columncount) + " columns."
);
csr.moveToPosition(-1); //Ensure that all rows are retrieved <<< added 20171016
while (csr.moveToNext()) {
String unobtainable = "unobtainable!";
String logstr = "Information for row " + Integer.toString(csr.getPosition() + 1) + " offset=" + Integer.toString(csr.getPosition());
for (int i=0; i < columncount;i++) {
logstr = logstr + "\n\tFor Column " + csr.getColumnName(i);
switch (csr.getType(i)) {
case Cursor.FIELD_TYPE_NULL:
logstr = logstr + " Type is NULL";
break;
case Cursor.FIELD_TYPE_FLOAT:
logstr = logstr + "Type is FLOAT";
break;
case Cursor.FIELD_TYPE_INTEGER:
logstr = logstr + " Type is INTEGER";
break;
case Cursor.FIELD_TYPE_STRING:
logstr = logstr + " Type is STRING";
break;
case Cursor.FIELD_TYPE_BLOB:
logstr = logstr + " Type is BLOB";
break;
}
String strval_log = " value as String is ";
String lngval_log = " value as long is ";
String dblval_log = " value as double is ";
String blbval_log = "";
try {
strval_log = strval_log + csr.getString(i);
lngval_log = lngval_log + csr.getLong(i);
dblval_log = dblval_log + csr.getDouble(i);
} catch (Exception e) {
strval_log = strval_log + unobtainable;
lngval_log = lngval_log + unobtainable;
dblval_log = dblval_log + unobtainable;
try {
blbval_log = " value as blob is " +
getBytedata(csr.getBlob(i),24);
} catch (Exception e2) {
e2.printStackTrace();
}
}
logstr = logstr + strval_log + lngval_log + dblval_log + blbval_log;
}
Log.d(CSU_TAG,logstr);
}
csr.moveToPosition(csrpos); // restore cursor position <<< added 20171016
}
public static String getTableInsertStatements(SQLiteDatabase db, String table) {
if (table.length() < 1) {
return "";
}
StringBuilder values = new StringBuilder();
//String values = "";
Cursor csr = getAllRowsFromTable(db,table,true,null);
long rowcount = csr.getCount();
while (csr.moveToNext()) {
for (int i=0; i < csr.getColumnCount(); i++) {
if (i==0) {
values.append(" (");
}
switch (csr.getType(i)) {
case Cursor.FIELD_TYPE_NULL:
values.append("null");
break;
case Cursor.FIELD_TYPE_INTEGER:
values.append(Long.toString(csr.getLong(i)));
break;
case Cursor.FIELD_TYPE_FLOAT:
values.append(Double.toString(csr.getDouble(i)));
break;
case Cursor.FIELD_TYPE_STRING:
String unescaped_string = csr.getString(i);
// NEED To ESCAPE HERE
values.append("'" + unescaped_string + "'");
break;
case Cursor.FIELD_TYPE_BLOB:
values.append("X'" + getBytedata(csr.getBlob(i),2147483647) + "'");
break;
}
// Add comma separator between values in current column unless last column
if (i < (csr.getColumnCount() - 1)) {
values.append(",");
}
// Add closing parenthesis after the last value of the row
if (i == csr.getColumnCount() - 1) {
values.append(")");
}
}
if (!csr.isLast()) {
values.append(",");
}
}
if (values.length() > 1 ) {
return "INSERT INTO " + table + " VALUES " + values.toString() + ";";
}
return "";
}
/**
* Return a hex string of the given byte array
* @param bytes The byte array to be converted to a hexadecimal string
* @param limit the maximum number of bytes;
* note returned string will be up to twice as long
* @return The byte array represented as a hexadecimal string
*/
private static String getBytedata(byte[] bytes, int limit) {
if (bytes.length < limit) {
return convertBytesToHex(bytes);
} else {
byte[] subset = new byte[limit];
System.arraycopy(bytes,0,subset,0,limit);
return convertBytesToHex(subset);
}
}
// HEX characters as a char array for use by convertBytesToHex
private final static char[] hexarray = "0123456789ABCDEF".toCharArray();
/**
* Return a hexadecimal string representation of the passed byte array
* @param bytes The byte array to be represented.
* @return The string representing the byte array as hexadecimal
*/
private static String convertBytesToHex(byte[] bytes) {
char[] hexstr = new char[bytes.length * 2];
for (int i=0; i < bytes.length; i++) {
int h = bytes[i] & 0xFF;
hexstr[i * 2] = hexarray[h >>> 4];
hexstr[i * 2 + 1] = hexarray[h & 0xF];
}
return new String(hexstr);
}
}
作为测试,我使用了以下内容: -
imgdbhlpr = new ImgDBHelper(this);
CommonSQLiteUtilities.logDatabaseInfo(imgdbhlpr.getWritableDatabase());
Cursor csr = CommonSQLiteUtilities.getAllRowsFromTable(imgdbhlpr.getWritableDatabase(),ImgDBHelper.TBLNAME,true,null);
CommonSQLiteUtilities.logCursorColumns(csr);
CommonSQLiteUtilities.logCursorData(csr);
Log.d("INSERTSTMNT",CommonSQLiteUtilities.getTableInsertStatements(imgdbhlpr.getWritableDatabase(),ImgDBHelper.TBLNAME))
生成的insert语句为: -
INSERT INTO images VALUES(1,'Image 001','image001.JPG'),(2,'Image 002','image002.JPG'),(3,'Image 003','image003.JPG'),(4,'Image 004','image004.JPG'),(5,'Image 005','image005.JPG'),(6,'Image 006','image006.JPG'),(7,'Image 007','image007.JPG'),(8,'Image 008','image008.JPG'),(9,'Image 009','image009.JPG'),(10,'Image 010' , 'image010.JPG');
整个输出是: -
12-14 17:59:00.253 2963-2963/? D/SQLITE_CSU: DatabaseList Row 1 Name=main File=/data/user/0/mjt.sqliteexamples/databases/myimagestore
12-14 17:59:00.254 2963-2963/? D/SQLITE_CSU: Database Version = 1
12-14 17:59:00.257 2963-2963/? D/SQLITE_CSU: Table Name = android_metadata Created Using = CREATE TABLE android_metadata (locale TEXT)
12-14 17:59:00.257 2963-2963/? D/SQLITE_CSU: Table = android_metadata ColumnName = locale ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
12-14 17:59:00.269 2963-2963/? D/SQLITE_CSU: Table Name = images Created Using = CREATE TABLE images(_id INTEGER PRIMARY KEY, description TEXT,path TEXT)
12-14 17:59:00.270 2963-2963/? D/SQLITE_CSU: Table = images ColumnName = _id ColumnType = INTEGER Default Value = null PRIMARY KEY SEQUENCE = 1
12-14 17:59:00.270 2963-2963/? D/SQLITE_CSU: Table = images ColumnName = description ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
12-14 17:59:00.270 2963-2963/? D/SQLITE_CSU: Table = images ColumnName = path ColumnType = TEXT Default Value = null PRIMARY KEY SEQUENCE = 0
12-14 17:59:00.274 2963-2963/? D/SQLITE_CSU: logCursorColumns invoked. Cursor has the following 3 columns.
12-14 17:59:00.274 2963-2963/? D/SQLITE_CSU: Column Name 1 is _id
12-14 17:59:00.274 2963-2963/? D/SQLITE_CSU: Column Name 2 is description
12-14 17:59:00.274 2963-2963/? D/SQLITE_CSU: Column Name 3 is path
12-14 17:59:00.274 2963-2963/? D/SQLITE_CSU: logCursorData Cursor has 10 rows with 3 columns.
12-14 17:59:00.274 2963-2963/? D/SQLITE_CSU: Information for row 1 offset=0
For Column _id Type is INTEGER value as String is 1 value as long is 1 value as double is 1.0
For Column description Type is STRING value as String is Image 001 value as long is 0 value as double is 0.0
For Column path Type is STRING value as String is image001.JPG value as long is 0 value as double is 0.0
......
12-14 17:59:00.277 2963-2963/? D/INSERTSTMNT: INSERT INTO images VALUES (1,'Image 001','image001.JPG'), (2,'Image 002','image002.JPG'), (3,'Image 003','image003.JPG'), (4,'Image 004','image004.JPG'), (5,'Image 005','image005.JPG'), (6,'Image 006','image006.JPG'), (7,'Image 007','image007.JPG'), (8,'Image 008','image008.JPG'), (9,'Image 009','image009.JPG'), (10,'Image 010','image010.JPG');
在SQLite Manager(我使用的工具)中,我使用CREATE TABLE images(_id INTEGER PRIMARY KEY, description TEXT,path TEXT)
创建表。
12-14 17:59:00.269 2963-2963/? D/SQLITE_CSU: Table Name = images Created Using = CREATE TABLE images(_id INTEGER PRIMARY KEY, description TEXT,path TEXT)
从输出中抓取)再次在SQLitae管理器中,我复制并粘贴了生成的INSERT语句并对其进行了处理,结果表为: -
注意!如前所述,这还没有完全检查,但可能只需要稍作修改(例如,没有进行转义,也没有检查双/浮点数或blob)。
使用伪随机生成的值对数据库进行测试。浮动似乎有效,BLOBS似乎有效。
e.g。
Source表看起来像(使用我在App中查看数据库信息的东西): -
虽然使用生成的insert语句创建的表看起来像(在SQLite Manager中): -
BLOBS,如果足够短,显示为十六进制,如果太长,则显示为BLOB size(??)
上面生成的INSERT语句为: -
INSERT INTO testtable2 VALUES
(1,'The quick fox was brown but couldn''t jump the fence, but tried so wasn''t that lazy.','The quick fox was brown but couldn''t jump the fence, but tried so wasn''t that lazy.',121.0), (2,1234.5678,X'4228290870402E6421527E45301777586D0945242F0F32766E4100046F6B6A053378633E2377126E3A1A71031D2B21522C3A74793B532D1E142B3E502D6A2D5778595D2316781D0D03183B136121396A222E1E1D20086E54',121.0), (3,X'5F1B681C033D7E7C60641146362F3E48276035220C200D','0.0.0.0',678946.0),
(4,'This is not a BLOB','0.0.0.0','The quick fox was brown but couldn''t jump the fence, but tried so wasn''t that lazy.'),
(5,1,'This is not a BLOB',1.0), ......