:mysql

在Xorm中使用Join和Extends标记

本文主要针对对Xorm已经有了一定了解的读者,如果您是第一次了解Xorm,请先阅读xorm操作手册

Xorm的基本操作都是比较简单的,可能大家也都比较熟悉了。今天主要讲解extends标记和join的使用。

一般我们会针对数据库中的每一个表,建立一个对应的结构体。比如:

type User struct {
    Id int64
    Name string
}

type Account struct {
    Id int64
    UserId int64 `xorm:"index"`
    Amount int64
}

type Car struct {
    Id int64
    UserId int64 `xorm:"index"`
    Type int
}

我们定义了三个结构体,对应数据库的三个表,我们在启动时通过:

engine.Sync2(new(User), new(Account), new(Car))

来进行数据库结构的同步。在这个数据库结构中,我们假设一个用户拥有一个Account,一个用户拥有多个Car。

OK。复杂需求来了。

1)我们需要获得所有的用户的姓名和对应的账户的余额:

type AccountUser struct {
    Account `xorm:"extends"`
    User `xorm:"extends"`
}

var accounts = make([]*AccountUser, 0)
engine.Table("account").Join("INNER", "user", "account.user_id = user.id").Find(&accounts)

OK。这样,我们就取出了user和对应的account,我们通过account.Account可以获取到Account的信息,通过account.User可以获取到User的信息。

这个是两个表Join,那么如果是三个表也是类似的做法。

2)我只需要用户名,不需要其它的内容:

type AccountUser struct {
    Account `xorm:"extends"`
    Name string
}
var accounts = make([]*AccountUser, 0)
engine.Table("account").Join("INNER", "user", "account.user_id = user.id").Find(&accounts)

其实我们代码也是差不多的,但是这里我们实际上在查询数据库的时候是查询了user表的所有内容的。只是在最后赋值到结构体时,按需赋值。

3)更复杂的,我们还想知道每人有几辆车。

type AccountUser struct {
    Account `xorm:"extends"`
    Name string
    NumCars int
}
var accounts = make([]*AccountUser, 0)
engine.Sql("select account.*, user.name, (select count(id) from car where car.user_id = user.id) as num_cars from account, user where account.user_id = user.id").Find(&accounts)

在这样的复杂需求下,我们使用了Sql函数和extends标记结合来完成这个操作。

MySQL中的insert ignore into, replace into, insert select, on duplicate key update的用法小结

在MySQL中进行条件插入数据时,可能会用到以下语句,现小结一下。我们先建一个简单的表来作为测试:

CREATE TABLE `books` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `NewIndex1` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert ignore into

当插入数据时,如出现错误时,如重复数据,将不返回错误,只以警告形式返回。所以使用ignore请确保语句本身没有问题,否则也会被忽略掉。例如:

insert ignore into books (name) values ('MySQL Manual')

on duplicate key update

当primary或者unique重复时,则执行update语句,如update后为无用语句,如id=id,则同1功能相同,但错误不会被忽略掉。例如,为了实现name重复的数据插入不报错,可使用一下语句:

insert into books (name) values ('MySQL Manual') on duplicate key update id = id

insert … select … where not exist

根据select的条件判断是否插入,可以不光通过primary 和 unique来判断,也可通过其它条件。例如:

insert into books (name) select 'MySQL Manual' from dual where not exists (select id from books where id = 1)

replace into

如果存在primary or unique相同的记录,则先删除掉。再插入新记录。

replace into books SELECT 1, 'MySQL Manual' FROM books

一个Python函数:执行MySQL的SQL文件

有些时候,我们需要通过python来执行SQL文件,那么这个函数就有用武之地了。调用之前确保安装了mysql。Linux和Windows应该是都可以用的,Linux下没有测试过。

from subprocess import Popen, PIPE

def excSQLFile(host, db, user, passwd, charset, filename):
    process = Popen('mysql -h%s -D%s -u%s -p%s --default-character-set=%s' \
        % (host, db, user, passwd, charset),
        stdout=PIPE, stdin=PIPE, shell=True)
    output = process.communicate('source ' + filename)[0]
    return output