LeftJoin/RightJoin/InnerJoin

  1. LeftJoin 左关联查询;
  2. RightJoin 右关联查询;
  3. InnerJoin 内关联查询;

其实我们并不推荐使用Join进行联表查询,特别是在数据量比较大、并发请求量比较高的场景中,容易产生性能问题,也容易提高维护的复杂度。建议您在确定有此必要的场景下使用。此外,您也可以参考 ORM链式操作-模型关联 章节,数据库只负责存储数据和简单的单表操作,通过ORM提供的功能在代码层面实现数据聚合。

使用示例:

// 查询符合条件的单条记录(第一条)
// SELECT u.*,ud.site FROM user u LEFT JOIN user_detail ud ON u.uid=ud.uid WHERE u.uid=1 LIMIT 1
g.Model("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid", 1).One()

// 查询指定字段值
// SELECT ud.site FROM user u RIGHT JOIN user_detail ud ON u.uid=ud.uid WHERE u.uid=1 LIMIT 1
g.Model("user u").RightJoin("user_detail ud", "u.uid=ud.uid").Fields("ud.site").Where("u.uid", 1).Value()

// 分组及排序
// SELECT u.*,ud.city FROM user u INNER JOIN user_detail ud ON u.uid=ud.uid GROUP BY city ORDER BY register_time asc
g.Model("user u").InnerJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.city").Group("city").Order("register_time asc").All()

// 不使用join的联表查询
// SELECT u.*,ud.city FROM user u,user_detail ud WHERE u.uid=ud.uid
g.Model("user u,user_detail ud").Where("u.uid=ud.uid").Fields("u.*,ud.city").All()

自定义数据表别名

// SELECT * FROM `user` AS u LEFT JOIN `user_detail` as ud ON(ud.id=u.id) WHERE u.id=1 LIMIT 1
g.Model("user", "u").LeftJoin("user_detail", "ud", "ud.id=u.id").Where("u.id", 1).One()
g.Model("user").As("u").LeftJoin("user_detail", "ud", "ud.id=u.id").Where("u.id", 1).One()

结合dao使用示例

// SELECT resource_task_schedule.id,...,time_window.time_window 
// FROM `resource_task_schedule` 
// LEFT JOIN `time_window` ON (`resource_task_schedule`.`resource_id`=`time_window`.`resource_id`) 
// WHERE (time_window.`status`="valid") AND (`time_window`.`start_time` <= 3600)
var (
	orm                = dao.ResourceTaskSchedule.Ctx(ctx)
	tsTable            = dao.ResourceTaskSchedule.Table()
	tsCls              = dao.ResourceTaskSchedule.Columns()
	twTable            = dao.TimeWindow.Table()
	twCls              = dao.TimeWindow.Columns()
	scheduleItems      []scheduleItem
)
orm = orm.FieldsPrefix(tsTable, tsCls)
orm = orm.FieldsPrefix(twTable, twCls.TimeWindow)
orm = orm.LeftJoinOnField(twTable, twCls.ResourceId)
orm = orm.WherePrefix(twTable, twCls.Status, "valid")
orm = orm.WherePrefixLTE(twTable, twCls.StartTime, 3600)
err = orm.Scan(&scheduleItems)
// SELECT DISTINCT resource_info.* FROM `resource_info` 
// LEFT JOIN `resource_network` ON (`resource_info`.`resource_id`=`resource_network`.`resource_id`) 
// WHERE (`resource_info`.`resource_id` like '%10.0.1.3%') 
// or (`resource_info`.`resource_name` like '%10.0.1.3%') 
// or (`resource_network`.`vip`like '%10.0.1.3%')  
// ORDER BY `id` Desc LIMIT 0,2
var (
	orm    = dao.ResourceInfo.Ctx(ctx).OmitEmpty()
	rTable = dao.ResourceInfo.Table()
	rCls   = dao.ResourceInfo.Columns()
	nTable = dao.ResourceNetwork.Table()
	nCls   = dao.ResourceNetwork.Columns()
)
orm = orm.LeftJoinOnField(nTable, rCls.ResourceId)
orm = orm.WherePrefix(rTable, do.ResourceInfo{
	AppId:        req.AppIds,
	ResourceId:   req.ResourceIds,
	Region:       req.Regions,
	Zone:         req.Zones,
	ResourceName: req.ResourceNames,
	Status:       req.Statuses,
	BusinessType: req.Products,
	Engine:       req.Engines,
	Version:      req.Versions,
})
orm = orm.WherePrefix(nTable, do.ResourceNetwork{
	Vip:      req.Vips,
	VpcId:    req.VpcIds,
	SubnetId: req.SubnetIds,
})
// Fuzzy like querying.
if req.Key != "" {
	var (
		keyLike = "%" + req.Key + "%"
	)
	whereFormat := fmt.Sprintf(
		"(`%s`.`%s` like ?) or (`%s`.`%s` like ?) or (`%s`.`%s`like ?) ",
		rTable, rCls.ResourceId,
		rTable, rCls.ResourceName,
		nTable, nCls.Vip,
	)
	orm = orm.Where(whereFormat, keyLike, keyLike, keyLike)
}
// Resource items.
err = orm.Distinct().FieldsPrefix(rTable, "*").Order(req.Order, req.OrderDirection).Limit(req.Offset, req.Limit).Scan(&res.Items)


















Content Menu

  • No labels

6 Comments

  1. 文档这里写db.Model,我找半天db是啥,折腾半天!!!最后发现这个db.Model就是g.Model。在GoFrame里面g是全局变量,任何应用里都可以直接用。db并没有定义为全局变量。

    建议将文档下面的内容更改一下:

    db.Model("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid", 1).One()  // db这个变量不是全局变量,用户没有定义,gogf框架里也没有定义,这样写会报找不到变量db

    g.Model("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid", 1).One() // g这个变量是全局变量,在gogf框架中已有定义,这样写不会找不到变量g
    1. 好,我们找个时间优化一下文档中的描述。

  2. jim

    orm = orm.FieldsPrefix(tsTable, tsCls)
    orm = orm.FieldsPrefix(twTable, twCls.TimeWindow)

    根据示例中的实际查询的时候,sql语句出现了问题导致报错;
    如:第一行中tsTable前缀的tsCls均会加上twTable的前缀,但是twTable的twCls.TimeWindow却不会如此,想问下如何解决这个问题.


  3. Ray

    dao写法  如果 on 条件的 字段名不一样怎么写呢 

    海亮 郭强 

  4. dao写法  如果 on 条件的 字段名不一样怎么写呢 

    同问,LeftJoinOnField 方法为什么只考虑相同的字段,业务中user_id=id这种不是很经常吗

    郭强 

  5. dao写法  如果 on 条件 字段名不一样。3个解决方案

    var (
    orm = dao.CpnCouponUser.Ctx(ctx)
    aaTable = dao.CpnCouponUser.Table()
    aaCls = dao.CpnCouponUser.Columns()
    bbTable = dao.CpnCouponStub.Table()
    bbCls = dao.CpnCouponStub.Columns()
    ccTable = dao.EswEshopWmProduct.Table()
    ccCls = dao.EswEshopWmProduct.Columns()
    couponUseAllItem = make([]*model.CouponUseAllItem, 0)
    )
    orm = orm.FieldsPrefix(aaTable, aaCls)
    orm = orm.FieldsPrefix(bbTable, bbCls.EswProductId)
    orm = orm.FieldsPrefix(ccTable, ccCls.Name)
    //如果需要分组取数据上面3行不用
    orm = orm.LeftJoin(bbTable, bbTable, aaTable+"."+aaCls.CpnStubId+"="+bbTable+"."+bbCls.Id)
    orm = orm.LeftJoin(ccTable, ccTable, bbTable+"."+bbCls.EswProductId+"="+ccTable+"."+ccCls.Id)
    //如果不需要分组取数据下面2行不用
    orm = orm.Fields(bbCls.EswProductId + "," + ccCls.Name + ",Count(0) AS couponCount")
    orm = orm.Group(bbCls.EswProductId, ccCls.Name)
    _ = orm.Scan(&couponUseAllItem)


    2用视图去做,然后用gen dao把视图搞出来。

    3直接用SQL去写,然后用g.modelRaw(sql)去实现。