簡(jiǎn)介
GreenDao是一個(gè)簡(jiǎn)化數(shù)據(jù)庫開發(fā)的ORM(Object Ralativational Mapping)來(對(duì)象關(guān)系映射)源框架垃喊,就是通過操作對(duì)象間接操作數(shù)據(jù)庫方式。
GreenDao的使用說明
-
gradle 配置中參數(shù)說明
- schemaVersion:指定數(shù)據(jù)庫schema版本號(hào)初家,遷移等操作會(huì)用到陌知。
- targetGenDir:生成數(shù)據(jù)庫文件的目錄仆葡。
- daoPackage:dao的包名志笼,包名默認(rèn)是entity所在的包纫溃。
-
實(shí)體類中注解說明
@Entity:表明這個(gè)實(shí)體類會(huì)在數(shù)據(jù)庫中生成一個(gè)與之相對(duì)應(yīng)的表紊浩,其中
nameInDb:可以自定義表名坊谁,表明該實(shí)體對(duì)應(yīng)數(shù)據(jù)庫中的那張表呜袁,默認(rèn)為實(shí)體類名阶界。
indexes:定義索引膘融,這里可跨越多個(gè)列氧映。
createInDb:如果是有多個(gè)實(shí)體都關(guān)聯(lián)這個(gè)表岛都,可以把多余的實(shí)體里面設(shè)置為false避免重復(fù)創(chuàng)建(默認(rèn)是true)臼疫。
schema:一個(gè)項(xiàng)目中有多個(gè)schema時(shí),表明要讓這個(gè)dao屬于哪個(gè)schema荣赶。
active:是否應(yīng)該生成更新/刪除/刷新方法。如果Entity定義了 @ToOne 或 @ToMany關(guān)系利诺,那么獨(dú)立于該值是有效的立轧。意為是否支持實(shí)體類之間update氛改,refresh胜卤,delete等操作葛躏。@Id:對(duì)應(yīng)數(shù)據(jù)表中的主鍵舰攒,是一條數(shù)據(jù)的唯一標(biāo)識(shí)摩窃。如果實(shí)體沒有聲明主鍵猾愿,默認(rèn)創(chuàng)建Long類型主鍵"_id"自增蒂秘。使用Long類型主鍵時(shí)可以通過@Id(autoincrement = true)設(shè)置為自增姻僧。
@Property(nameInDb = "USER_NAME" ):可以自定義字段名撇贺,注意外鍵不能使用該屬性显熏。表明這個(gè)屬性對(duì)應(yīng)數(shù)據(jù)表中的 USER_NAME 字段晒屎。
@NotNull:該屬性值不能為空鼓鲁。
@Transient:該屬性不會(huì)被存入數(shù)據(jù)庫中骇吭。
@Unique:表明該屬性在數(shù)據(jù)庫中只能有唯一值燥狰。
@Index:創(chuàng)建一個(gè)索引龙致。通過name設(shè)置索引別名目代,也可以通過unique給索引添加約束榛了。
@Convert:指定一個(gè)PropertyConverter用于支持自定義類型(沒用過)霜大。
@ToOne:定義自己與一個(gè)實(shí)體對(duì)象的關(guān)系战坤。
@ToMany:定義自己與多個(gè)實(shí)體對(duì)象的關(guān)系(可不與@ToOne聯(lián)合使用)湖笨。@ToMany的屬性referencedJoinProperty慈省,類似于外鍵約束边败。
@JoinProperty:對(duì)于更復(fù)雜的關(guān)系笑窜,可以使用這個(gè)注解標(biāo)明目標(biāo)屬性的源屬性排截,起關(guān)聯(lián)作用。
@JoinEntity:如果你在做多對(duì)多的關(guān)系脱吱,有其他的表或?qū)嶓w參與箱蝠,可以給目標(biāo)屬性添加這個(gè)額外的注解宦搬。
@OrderBy:指定{@ToMany}關(guān)系的相關(guān)集合的排序间校,(propertyA, propertyB)默認(rèn)為按主鍵ASC排序撇簿。
@Generated:這個(gè)是build后greendao自動(dòng)生成的四瘫,這個(gè)注解理解為防止重復(fù)找蜜,每一塊代碼生成后會(huì)加個(gè)hash作為標(biāo)記洗做。
表關(guān)聯(lián)(一對(duì)一诚纸,一對(duì)多)舉例
現(xiàn)有兩張表:作者表和文章表畦徘,文章表中有一列authorId對(duì)應(yīng)作者表的id井辆。希望可以通過文章的id查詢作者信息杯缺。
一對(duì)一:
@Entity(nameInDb = "CsYdd",createInDb = true,indexes = {@Index(value = "id",unique = true)}) //value值必須是主鍵
public class Article {
@Id(autoincrement = true)
public long id; //id是主鍵
@SerializedName("is_FORCEEEE") //json解析換名
@Property(nameInDb = "is_FORCEEEE2") //db中換名
public boolean isFirst;
private long authId; //該authId就是Author的主鍵id萍肆,注意類型一定要相同,這里都為long類型
@ToOne(joinProperty = "authId")
private Author bean;
}
一對(duì)多:
@Entity(nameInDb = "CsYEE",createInDb = true,indexes = {@Index(value = "id",unique = true)})
public class Author {
@Id
public long id;
@ToMany(referencedJoinProperty = "authId") //authId是Article中與Author關(guān)聯(lián)的參數(shù)名
private List<Article> list;
}
代碼調(diào)用:
ArticleDao dao = daoSession.getArticleDao();
Article load = dao.load(id);
Author bean = load.getBean();
AuthorDao dao = daoSession.getArticleDao();
Author load = dao.load(id);
List<Article> list = load.getList();
多對(duì)多:(例如:老師與學(xué)生關(guān)系)
@Entity public class Teacher {
@Id(autoincrement = true) private Long id;
private String name;
// 對(duì)多碉纳,@JoinEntity注解:entity 中間表;sourceProperty 實(shí)體屬性奴愉;targetProperty 外鏈實(shí)體屬性
@ToMany
@JoinEntity(entity = JoinStudentToTeacher.class, sourceProperty = "tid", targetProperty = "sid")
private List<Student> students;
}
@Entity public class Student {
@Id private Long id;
private String name;
//對(duì)多锭硼,@JoinEntity注解:entity 中間表檀头;sourceProperty 實(shí)體屬性暑始;targetProperty 外鏈實(shí)體屬性
@ToMany
@JoinEntity(entity = JoinStudentToTeacher.class, sourceProperty = "sid", targetProperty = "tid")
private List<Teacher> teachers;
}
//借助的中間關(guān)系網(wǎng)
@Entity public class JoinStudentToTeacher {
@Id(autoincrement = true) private Long id;
//和teacher關(guān)聯(lián)的id
private Long tid;
//和student關(guān)聯(lián)的id
private Long sid;
}
greenDao方式測(cè)試
private void cs_toMany_toMany() {
TeacherDao TeacherDao = MyApplication.getDaoSession().getTeacherDao();
StudentDao studentDao = MyApplication.getDaoSession().getStudentDao();
JoinStudentToTeacherDao spDao = MyApplication.getDaoSession().getJoinStudentToTeacherDao();
Teacher p1 = new Teacher();
p1.setId(1L);
p1.setName("teacherOne");
Teacher p2 = new Teacher();
p2.setId(2L);
p2.setName("teacherTwo");
Teacher p3 = new Teacher();
p3.setId(3L);
p3.setName("teacherThree");
Student stu1 = new Student();
stu1.setId(1L);
stu1.setName("stu1");
Student stu2 = new Student();
stu2.setId(2L);
stu2.setName("stu2");
Student stu3 = new Student();
stu3.setId(3L);
stu3.setName("stu3");
// 模擬 多對(duì)多關(guān)系牙肝,建立關(guān)系網(wǎng)
//p1有stu1 stu2 stu3 配椭,那么反過來stu123都有p1
JoinStudentToTeacher sp1 = new JoinStudentToTeacher();
sp1.setTid(1L);
sp1.setSid(1l);
JoinStudentToTeacher sp2 = new JoinStudentToTeacher();
sp2.setTid(1L);
sp2.setSid(2L);
JoinStudentToTeacher sp3 = new JoinStudentToTeacher();
sp3.setTid(1L);
sp3.setSid(3L);
//p2有stu1 stu2 stu3 股缸,那么反過來stu123都有p2
JoinStudentToTeacher sp4 = new JoinStudentToTeacher();
sp4.setTid(2L);
sp4.setSid(1L);
JoinStudentToTeacher sp5 = new JoinStudentToTeacher();
sp5.setTid(2L);
sp5.setSid(2L);
JoinStudentToTeacher sp6 = new JoinStudentToTeacher();
sp6.setTid(2L);
sp6.setSid(3L);
TeacherDao.insertOrReplace(p1); //也可用insertOrReplaceInTx()方式直接插入List
TeacherDao.insertOrReplace(p2);
TeacherDao.insertOrReplace(p3);
studentDao.insertOrReplace(stu1);
studentDao.insertOrReplace(stu2);
studentDao.insertOrReplace(stu3);
spDao.insertOrReplace(sp1);
spDao.insertOrReplace(sp2);
spDao.insertOrReplace(sp3);
spDao.insertOrReplace(sp4);
spDao.insertOrReplace(sp5);
spDao.insertOrReplace(sp6);
List<Teacher> Teachers = TeacherDao.queryBuilder().build().list();
for (Teacher Teacher : Teachers) {
Log.d("GreenDao","Teacher:"+Teacher.toString());
}
}
容易忽略的:
1.如果是list或者數(shù)組類型的屬性XX,只有g(shù)etXX方法坎背,沒有setXX方法得滤,但可用GreenDao的insertOrReplaceInTx()方法設(shè)置懂更。
2.如果你要打印 @ToOne對(duì)應(yīng)的bean類時(shí),要先調(diào)用getXXX方法龄捡,而不是直接打印對(duì)象(因?yàn)闆]有賦值聘殖,而是在getXX的時(shí)候才賦值的)
3.以上三種方法奸腺,刪除時(shí)候都不會(huì)關(guān)聯(lián)刪除突照。
GreenDao的其他方法
1 inser() 插入一條數(shù)據(jù)
2 insertInTx() 批量插入數(shù)據(jù)讹蘑,比如List
3 insertOrReplace() 插入數(shù)據(jù)座慰,傳入的對(duì)象主鍵如果存在于數(shù)據(jù)庫中角骤,有則更新,否則插入
4 insertOrReplaceInTx() 批量插入數(shù)據(jù)背桐,同上
5 save()比insertOrReplace()更有效率链峭,但其會(huì)先判斷對(duì)象是否有Key值弊仪,有則采用update方式更新(若在數(shù)據(jù)庫中無任何數(shù)據(jù)励饵,則此數(shù)據(jù)不會(huì)保存到數(shù)據(jù)庫)役听,無則采用insert方式插入典予。
6 insertWithoutSettingPk() 不需要設(shè)置主鍵屬性瘤袖,因?yàn)閮H對(duì)主鍵為L(zhǎng)ong類型自增有效捂敌,String類型主鍵會(huì)Error黍匾。
7 deleteAll() 刪除相應(yīng)表的全部數(shù)據(jù)(清空相應(yīng)表)呛梆。
8 deleteByKey() 刪除給定PK的實(shí)體填物。
9 deleteByKeyInTx(K... keys) 使用事務(wù)刪除數(shù)據(jù)庫中給定鍵的所有實(shí)體滞磺。批量刪除击困。
10 delete(T entity) entity的id屬性必須有值,否則報(bào)錯(cuò)阅茶。就是刪除與entity主鍵值相同的數(shù)據(jù)脸哀,其他數(shù)據(jù)值與表中數(shù)據(jù)值不一致時(shí)撞蜂,會(huì)刪除蝌诡。
11 deleteInTx(T... entities) 使用事務(wù)刪除數(shù)據(jù)庫中給定的實(shí)體浦旱。批量刪除。每個(gè)entity的id屬性必須有值尼酿,否則報(bào)錯(cuò)裳擎。
12 update(T entity) entity的id屬性必須有值思币,否則報(bào)錯(cuò)谷饿。若entity的id值表中不存在時(shí)博投,不會(huì)報(bào)錯(cuò)毅哗。
13 updateInTx(T... entities) 使用事務(wù)更新數(shù)據(jù)庫中給定的實(shí)體虑绵。批量更新翅睛。
14 load(K key) 加載給定PK的實(shí)體捕发。傳入:key or null。返回:該實(shí)體 或 null充石。
15 loadByRowId(long rowId) 加載給定RowId的實(shí)體骤铃。傳入:key or null惰爬。返回:該實(shí)體 或 null撕瞧。
16 loadAll() 從數(shù)據(jù)庫加載所有可用的實(shí)體。
17 unique() 返回非空的結(jié)果巩掺,否則拋出異常胖替。
18 uniqueOrThrow() 返回非空的結(jié)果独令,否則拋出異常燃箭。
19 queryBuilder()用法示例如下:
mCustomerBeanDao.queryBuilder()
.limit(3) //取前3條數(shù)據(jù)
.offset(2) //偏移量(必須與limit()配合使用)
.distinct() //去重
.orderDesc(CustomerBeanDao.Properties.Adcode) //降序---descending
.orderAsc(CustomerBeanDao.Properties.District) //升序---ascending
.orderCustom(CustomerBeanDao.Properties.Adcode,"") //偏好排序---custom---定制
.orderRaw("") //使用原始sql排序
.preferLocalizedStringOrder() //使用本地化排序
.stringOrderCollation("COLLATE NOCASE") //orderAsc和orderAsc自定義排序
.where(CustomerBeanDao.Properties.CustName.like("dfsfs%")) //查詢條件招狸,參數(shù)間關(guān)系為 and
.whereOr(CustomerBeanDao.Properties.AreaName.like("dsfsf%") //查詢條件瓢颅,參數(shù)間關(guān)系為 or
,CustomerBeanDao.Properties.Address.eq("")) //n個(gè)查詢條件
.build()
.list();
查詢條件有:
between(Object value1, Object value2): BETWEEN … AND …
eq(Object value): equal (‘=’)
notEq(Object value): not equal (‘<>’)
gt(Object value): than (‘>’) ---- greater than
lt(Object value): less than (‘<’) ---less than
ge(Object value): greater or equal (‘>=’)
le(Object value): less or equal (‘<=’)
like(String value): LIKE
isNotNull(): IS NOT NULL
isNull(): IS NULL
in(Object… inValues): IN (…, …, …)
notIn(Object… notInValues): NOT IN (…, …, …)
in(Collection< ?> inValues): IN (…, …, …)
notIn(Collection< ?> notInValues): NOT IN (…, …, …)
queryBuilder.or()用法,借用一個(gè)網(wǎng)上的例子說明:
獲取1970年10月或之后出生的名為“Tom”的用戶信息(對(duì)應(yīng)的sql:where name = "Tom" and ((year = 1970 and month >=10) or (year >1970)))
QueryBuilder<User> qb = userDao.queryBuilder();
//要特別注意qb.or(,qb.and())中嵌套的層級(jí)結(jié)構(gòu)
qb.where(Properties.FirstName.eq("Tom"),qb.or(Properties.YearOfBirth.gt(1970),qb.and(Properties.YearOfBirth.eq(1970),Properties.MonthOfBirth.ge(10))));
List<User> youngJoes = qb.list();
20 or\and(WhereCondition... condMore) 在where或whereOr中使用木人,condMore參數(shù)間關(guān)系為or\and
21 list() 執(zhí)行查詢并將返回一個(gè)包含所有entity的list為結(jié)果醒第,直接加載在內(nèi)存中(存在緩存問題)稠曼。
22 listLazy() 當(dāng)真正用到數(shù)據(jù)時(shí)(訪問entity的屬性時(shí))霞幅,才會(huì)查詢數(shù)據(jù)庫司恳。
23 listLazyUncached() 也實(shí)現(xiàn)了懶加載技術(shù)扔傅,但是返回結(jié)果list沒有保存在內(nèi)存中,沒法復(fù)用试读,每次都會(huì)向數(shù)據(jù)庫查詢真正的數(shù)據(jù)鹏往。
24 listIterator() 執(zhí)行查詢并將結(jié)果作為列表迭代器返回伊履;確保關(guān)閉它以關(guān)閉底層游標(biāo)唐瀑。一旦迭代器完全迭代哄辣,游標(biāo)就會(huì)關(guān)閉力穗。
25 queryRawCreate() 基于給定的原始SQL創(chuàng)建一個(gè)可重復(fù)的{查詢}對(duì)象气嫁,可以在這里傳遞任何WHERE子句和參數(shù)寸宵。
26 queryRaw() 一個(gè)原始樣式查詢梯影,可以在這里傳遞任何WHERE子句和參數(shù)甲棍。
27 queryRawCreateListArgs() 基于給定的原始SQL創(chuàng)建一個(gè)可重復(fù)的{查詢}對(duì)象感猛,您可以在這里傳遞任何WHERE子句和參數(shù)唱遭。
28 多線程查詢:
29 rx():返回在IO線程發(fā)射事件的 Observables
30 rxPlain():返回沒有設(shè)置無線程調(diào)度的 Observables
31 detach() 將一個(gè)實(shí)體從會(huì)話中拆分拷泽。后續(xù)查詢結(jié)果不會(huì)返回此對(duì)象袖瞻。
32 detachAll() 所有的 同上
33 refresh() 通過從數(shù)據(jù)庫重新加載重置該實(shí)體的所有本地更改屬性聋迎。
34 daoSession.clear() 清除daoSession的緩存
35 dao.detachAll() 清除指定dao類的緩存
36 QueryBuilder.LOG_SQL = true; //打印SQL標(biāo)志
37 QueryBuilder.LOG_VALUES = true; //打印參數(shù)標(biāo)志
執(zhí)行原始SQL查詢舉例:(目的:根據(jù)一個(gè)表的數(shù)據(jù)查另一個(gè)表中數(shù)據(jù))
方法一霉晕,被拼接在where之后添加查詢條件:
Query<User> query = userDao.queryBuilder().where(new StringCondition("_ID in " +"(SELECT USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)")).build();
方法二牺堰,被拼接在查詢語句的SELECT和實(shí)體之后:
Query<User> query = userDao.queryRawCreate(", Table2 G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin"); //注意:實(shí)體User默認(rèn)別名為 T伟葫,Table2前邊的","是表間的分隔符
方法三筏养,Database方式:
Cursor cursor = daoSession().getDatabase().rawQuery(sql,selectionArgs);
數(shù)據(jù)庫升級(jí)
Android數(shù)據(jù)庫升級(jí)涉及到的問題:
1. 若不升級(jí)渐溶,是不能增加新表弄抬,也不能修改或增加舊表字段的眉睹,除非卸載APP重裝(即刪除數(shù)據(jù)庫并重建,但丟數(shù)據(jù)),否則會(huì)crash斋配;
2. 升級(jí)版本號(hào)艰争,觸發(fā)onUpgrade()方法桂对,可手動(dòng)進(jìn)行新舊表的增蕉斜、刪、改等操作机错;
3. 實(shí)現(xiàn)數(shù)據(jù)庫升級(jí)方案:a.采用增加新表,同時(shí)修改或增減舊表字段青瀑;b.舊表改名為臨時(shí)表斥难,新建表蘸炸,導(dǎo)入數(shù)據(jù)搭儒,如上方式;
public final class MigrationHelper {
public static void migrate(SQLiteDatabase sqliteDatabase, Class<? extends AbstractDao<?, ?>>... daoClasses) {
StandardDatabase db = new StandardDatabase(sqliteDatabase);
generateNewTablesIfNotExists(db, daoClasses);
generateTempTables(db, daoClasses);
dropAllTables(db, true, daoClasses);
createAllTables(db, false, daoClasses);
restoreData(db, daoClasses);
}
public static void migrate(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateNewTablesIfNotExists(db, daoClasses);
generateTempTables(db, daoClasses);
dropAllTables(db, true, daoClasses);
createAllTables(db, false, daoClasses);
restoreData(db, daoClasses);
}
private static void generateNewTablesIfNotExists(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
reflectMethod(db, "createTable", true, daoClasses);
}
private static void generateTempTables(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("CREATE TEMP TABLE ").append(tempTableName);
insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
private static void dropAllTables(StandardDatabase db, boolean ifExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
reflectMethod(db, "dropTable", ifExists, daoClasses);
}
private static void createAllTables(StandardDatabase db, boolean ifNotExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
reflectMethod(db, "createTable", ifNotExists, daoClasses);
}
/**
* dao class already define the sql exec method, so just invoke it
*/
private static void reflectMethod(StandardDatabase db, String methodName, boolean isExists, @NonNull Class<? extends AbstractDao<?, ?>>... daoClasses) {
if (daoClasses.length < 1) {
return;
}
try {
for (Class cls : daoClasses) {
Method method = cls.getDeclaredMethod(methodName, Database.class, boolean.class);
method.invoke(null, db, isExists);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
private static void restoreData(StandardDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
// get all columns from tempTable, take careful to use the columns list
List<String> columns = getColumns(db, tempTableName);
ArrayList<String> properties = new ArrayList<>(columns.size());
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (columns.contains(columnName)) {
properties.add(columnName);
}
}
if (properties.size() > 0) {
final String columnSQL = TextUtils.join(",", properties);
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(columnSQL);
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(columnSQL);
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(dropTableStringBuilder.toString());
}
}
private static List<String> getColumns(StandardDatabase db, String tableName) {
List<String> columns = null;
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);
if (null != cursor && cursor.getColumnCount() > 0) {
columns = Arrays.asList(cursor.getColumnNames());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
if (null == columns)
columns = new ArrayList<>();
}
return columns;
}
}
然后在初始化時(shí)用到的 UpgradeHelper 類的onUpgrade方法中添加:
public class UpgradeHelper extends DaoMaster.OpenHelper {
public UpgradeHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
MigrationHelper.migrate(db, PortraitPhotoDao.class, FeatureDao.class, PhotoJoinUserDao.class,
UserPhotoDao.class);
}
}
升級(jí)方案參考于:https://blog.csdn.net/zhanlv/article/details/82425709
SQL中常用命令
對(duì)表結(jié)構(gòu)操作命令:
修改表名:
rename table 舊表名 to 新表名修改表選項(xiàng):
alter table 表名 表選項(xiàng) [=] 新值新增字段:
alter table 表名 add [column] 新字段名 列類型[列屬性] [位置first/after 字段名](默認(rèn)加到表的最后面)字段位置:字段想要存放的位置铃岔,first:在某某之間(最前面)毁习,第一個(gè)字段纺且;after 字段名:放在某個(gè)具體的字段后(默認(rèn)的)刪除字段
alter table 表名 drop 字段名修改字段名
alter table 表名 change 舊字段名 新字段名 字段類型[列屬性] [位置屬性] (修改名字需要修改字段類型)修改字段類型(屬性):
alter table 表名 modify 字段名 新類型 [新屬性] [新位置]刪除表結(jié)構(gòu)
drop table 表名[,表名2....]; 可同時(shí)刪除多個(gè)表小結(jié):對(duì)表結(jié)構(gòu)操作時(shí)载碌,都需要用特定字段如alter,并且需要特指table及名稱嫁艇,但下邊對(duì)數(shù)據(jù)操作步咪,則不需要特指table益楼。
對(duì)表中數(shù)據(jù)操作命令:
- 增:insert into 表名(字段列表,當(dāng)插入所有字段時(shí)可省略) values(對(duì)應(yīng)字段列表)
- 刪:delete from 表名 [where條件] 如果沒有where條件静袖,意味著系統(tǒng)會(huì)自動(dòng)刪除該表所有數(shù)據(jù)(慎用)
- 改:update 表名 set 字段名 = 新值 [where條件];
- 查:select 字段列表 from 表名 from 表名 where 字段名=值 and 字段名=值 order by name DESC, age ASC //字段列表使用‘ 坠陈, ’隔開
需要注意:
寫的順序:select ... from... where.... group by... having... order by..
執(zhí)行順序:from... where...group by... having.... select ... order by...
- group by數(shù)據(jù)分組舉例:
方法一:
SELECT * FROM (select a.* from new_table a inner join new_table b on a.name = b.name group by name order by time desc) c GROUP BY c.kefuid
方法二:
SELECT * FROM (select * from new_table group by id order by time desc) c GROUP BY c.kefuid
- having條件語句:
having與where有類似作用仇矾,當(dāng)WHERE 關(guān)鍵字無法與合計(jì)函數(shù)一起使用時(shí)使用:
例如:我們希望查找訂單總金額少于 2000 的客戶:
SELECT Customer,SUM(OrderPrice) FROM Orders GROUP BY Customer HAVING SUM(OrderPrice)<2000
然而贮匕,現(xiàn)在我們希望查找客戶 "Bush" 或 "Adams" 擁有超過 1500 的訂單總金額刻盐,則需要這樣:
SELECT Customer,SUM(OrderPrice) FROM Orders WHERE Customer='Bush' OR Customer='Adams'
GROUP BY Customer HAVING SUM(OrderPrice)>1500
- SUM () 函數(shù)返回?cái)?shù)值列的總數(shù):
SELECT COUNT(column_name) FROM table_name //函數(shù)返回指定列的值的數(shù)目值(NULL 不計(jì)入)
SELECT COUNT(*) FROM table_name //函數(shù)返回表中的記錄數(shù)目值
SELECT COUNT(DISTINCT column_name) FROM table_name //函數(shù)返回指定列的不同值的數(shù)目值
- AVG()取平局值:如我們希望找到 OrderPrice 值高于 OrderPrice 平均值的客戶
SELECT Customer FROM Orders WHERE OrderPrice>(SELECT AVG(OrderPrice) FROM Orders)
- inner join
nner join(等值聯(lián)接) 從兩表中抽取出聯(lián)結(jié)字段相等的行數(shù)據(jù)敦锌,整合到一起后返回。
left join(左聯(lián)接) 將左表中的所有數(shù)據(jù)和右表中聯(lián)結(jié)字段相等的數(shù)據(jù),整合到一起后返回。
right join(右聯(lián)接) 將右表中的所有記錄和左表中聯(lián)結(jié)字段相等的數(shù)據(jù),整合到一起后返回汉买。
inner join 連接兩個(gè)數(shù)據(jù)表的用法:
SELECT * FROM 表1 INNER JOIN 表2 ON 表1.字段號(hào)=表2.字段號(hào)
inner join 連接三個(gè)數(shù)據(jù)表的用法:
SELECT * FROM (表1 INNER JOIN 表2 ON 表1.字段號(hào)=表2.字段號(hào)) INNER JOIN 表3 ON 表1.字段號(hào)=表3.字段號(hào)
總結(jié):
只要兩個(gè)表的公共字段有匹配值录别,就將這兩個(gè)表中的記錄組合起來,類似數(shù)學(xué)中的取并集葫男,并集(合并相同部分)。
推薦幾個(gè)網(wǎng)址:
? ?? 查看 inner join on 用法示例
? ?? sql語法大全
? ?? sql舉例大全
? ?? Mysql教程(Windows)
網(wǎng)上相關(guān)資源很多旺遮,在此記錄只為方便查看耿眉。