Stack Overflow,
我试图了解如何使用String.format()为我的Android应用程序创建一个sqlite数据库。
我有一个扩展SQLiteOpenHelper的公共类和一个包含私有静态final字符串的私有内部类,我打算将其作为我数据库的列名。
音乐数据库类代码
public class SaturnMusicDatabase extends SQLiteOpenHelper{
private Context mContext;
// Necessary public constructor to use SQLiteOpenHelper
public SaturnMusicDatabase(Context context){
super(context, "SaturnMusic.db"), null,1);
mContext = context;
}
// The columns beginning with an underscore are the primary key
private static final class Songs{
private static final String TABLE = "songs";
private static final String COL_ARTIST ="_artist";
private static final String COL_ALBUM="_album";
private static final String COL_TITLE ="_title";
private static final String COL_GENRE = "genre";
private static final String COL_LENGTH ="length";
private static final String COL_Number ="number";
}
@Override
public void onCreate(SQLiteDatabase db) {
String queryMakeSong = String.format
("create table %s (primary key(%s, %s, %s)%s, %s, %s)",
Songs.TABLE, Songs.COL_ARTIST, Songs.COL_ALBUM, Songs.COL_TITLE,
Songs.COL_GENRE, Songs.COL_LENGTH, Songs.COL_Number);
db.execSQL(queryMakeSong);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
我对create语句感到困惑。我理解String.format()如何工作的方式是%符号后跟一个修饰符确定格式化传递给函数的数据时要使用的数据类型。
我的目的是创建一个名为歌曲的表格,其中包含六个字段,其中三个是主键:艺术家,专辑和标题。
字段名称应该是字符串是有道理的,所以我选择使用' s'修改。这是否意味着将存储在这些字段中的数据将是字符串?或者它是否意味着字段名称是字符串,我必须指定这些字段在create table语句中应该包含哪些数据类型?
如果是前者,那不是我想要的所有领域。像LENGTH和NUMBER这样的东西应该存储整数。这让我觉得他们应该使用'改性剂。
如果我的任何语法错误,请分享,以及我如何纠正它。
答案 0 :(得分:1)
我理解String.format()的工作方式是%符号 后跟一个修饰符确定格式化时要使用的数据类型 传递给函数的数据。
我相信 %
之后是参数的索引,即%1 ...替换第一个参数%2 ...第二个等等。
$
位于类型/转化之前。
所以(猜测)你会尝试: -
..... create table %1$s (primary key(%2$s, %3$s, %4$s)%5$s, %6$s, %7$s)"
这是否意味着将存储在这些字段中的数据将是 是字符串?
完全没有。事实上,SQLite非常灵活,你可以在任何列中存储任何类型的值( 例外是rowid列,它始终是TYPE INTEGER ,这是由default通常是透明的;将列定义为?? INTEGER PRIMARY KEY
或?? INTEGER PRIMARY KEY AUTOINCREMENT
)会为名为??的rowid列创建别名(其中??将是有效的列名,例如 _id )。
在你没有指定列类型的情况下,根据规则(#3),列类型都将是BLOB -
如果列的声明类型包含字符串" BLOB"或者如果没有 指定了类型,然后该列具有关联BLOB。
但是,当实际存储值时,存储类将起作用并应用以下规则: -
具有亲和力BLOB的列不喜欢一个存储类 另一个并没有尝试强制来自一个存储类的数据 到另一个。
即。数据将根据所应用数据的类型进行存储。
您可能希望查看以上所基于的Datatypes In SQLite Version 3 。
作为这个表的一个例子: -
可以拥有数据(The Legend描述颜色编码): -
这表明每个行/列组合实际上都有自己的TYPE。
或者它是否意味着字段名称是字符串,我必须指定 这些字段在create table语句中应该包含哪些数据类型?
从上面你可能不喜欢。
我有一个包含私有静态final的私有内部类 字符串
您可能会发现将名称设为public static final String
会更有用。然后,您可以在整个过程中使用该名称的单一定义。
即。您可能希望在某个时间访问数据,在这种情况下,您可能需要一个列名,比如从表中获取该列的数据。
比较以下内容: -
Cursor csr = db.query("snogs",null,null,null,null,null.null); // What idiot used snogs instead of songs?????
Cursor csr = db.query(Songs.TABLE,null,null,null,null,null,null);
前者=表未找到错误,因为我无意中闻到了(这里我再去一次:))歌曲不正确(显然是故意的)。
后者很难在许多IDE中出错,因为Snogs.TABLE
在编辑器中显示为不正确且无法编译。
在检索数据时使用列名(尤其是来自单一来源)而不是硬编码偏移不太可能导致问题。而不是
String artist = csr.getString(5); // what column is this????
啰嗦得多: -
String artist = csr.getString(csr.getColumnIndex(Songs.COL_Number));
不太可能导致问题,例如: -
假设您修改了表以包含另一列,并且该列位于最后一列之前,那么前者将获得错误的数据,直到更改为6,而后者不需要更改。
答案 1 :(得分:-1)
你不应该。请改用绑定变量。使用String.format使您容易受到SQL注入安全漏洞的攻击,绑定变量可以避免这种情况。如果您没有进行动态查询(比如创建表),那么只需输入原始SQL而不是格式化,在维护查询时,它将更加易读。
但是要回答你的问题 - 格式中的符号与db中存储的数据类型无关,因为String.format对数据库一无所知,或者它用于数据库查询。它只输出格式化的字符串。如果您在该字符串中输入的实际值是数字,请使用%d。如果它的字符串如表名,列名等,请使用%s。