一条sql查出树形结构数据

当前的问题:同一张表中存放省市区县的数据,如何通过一条SQL语句将省市区县都查询出来,
且省级包含所有的市级列表,市级中又包含县级的数据。

想法:利用mybatis集合的嵌套查询(collection)

数据格式如下:

Java实体类如下:

public class Area implements Serializable{

	private static final long serialVersionUID = 1L;

	/**
	 * 主键id
	 */
	private Integer id;
	/**
	 * 地区名称
	 */
    private String name;
    /**
     * 地区编码
     */
    private Integer areaId;
    /**
     * 上一级地区编码
     */
    private Integer parentId;
    /**
    * 下一级地区列表
    */
    private List<Area> subAreas;

    ...getter 和 setter 方法...
}

xml:

支持两层嵌套的例子

  <!-- 同表级联查询(支持两层嵌套查询) -->
  <resultMap type="cn.edu.ntu.entity.Area" id="areasOther">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="area_id" jdbcType="INTEGER" property="areaId" />
    <result column="parent_id" jdbcType="INTEGER" property="parentId" />
    <collection property="subAreas" ofType="cn.edu.ntu.entity.Area" columnPrefix="b">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="area_id" jdbcType="INTEGER" property="areaId" />
        <result column="parent_id" jdbcType="INTEGER" property="parentId" />
    </collection>
    <!-- 使用columnPrefix简化书写,否则需要写成
    	<collection property="subAreas" ofType="cn.edu.ntu.entity.Area" >
	        <id column="bid" jdbcType="INTEGER" property="id" />
	        <result column="bname" jdbcType="VARCHAR" property="name" />
	        <result column="barea_id" jdbcType="INTEGER" property="areaId" />
	        <result column="bparent_id" jdbcType="INTEGER" property="parentId" />
	    </collection>
	     column的值与sql语句中的命名对应
     -->
  </resultMap>

  <!--因为是一对多的关系,用collection-->
  <select id="queryAllCity" resultMap="areasOther">
    select     
	    a.id, a.name, a.area_id, 
	    b.id bid, b.name bname, b.area_id barea_id
    from area a 
    left join area b on b.parent_id = a.area_id
    where a.parent_id is null
  </select>

测试方法:

public class MybatisTest {

	@Test
	public void test(){
		ApplicationContext application = 
            new ClassPathXmlApplicationContext("classpath*:spring/applicationContext.xml");
		
		AreaMapper areaMapper = application.getBean(AreaMapper.class);
		List<Area> areaList = areaMapper.queryAllCity();
		System.out.println(areaList.size());
		System.out.println(areaList.get(0).getSubAreas().size());
		System.out.println(JsonUtils.objectToJson(areaList));
		
	}
}

运行结果:

结论:

    从上面的的测试数据可以看出已经支持两层嵌套,但是如果还要往id为“areasOther”的<resultMap>的<collection>中再嵌套一层<collection>,目的是支持三层嵌套,暂时不知道如何操作???

尝试失败的案例:

  <!-- 同表级联查询(支持三层嵌套查询的测试) -->
  <resultMap type="cn.edu.ntu.entity.Area" id="areasOther">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="area_id" jdbcType="INTEGER" property="areaId" />
    <result column="parent_id" jdbcType="INTEGER" property="parentId" />
    <collection property="subAreas" ofType="cn.edu.ntu.entity.Area" columnPrefix="b">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="area_id" jdbcType="INTEGER" property="areaId" />
        <result column="parent_id" jdbcType="INTEGER" property="parentId" />
        <collection property="subAreas" ofType="cn.edu.ntu.entity.Area" columnPrefix="c">
            <id column="id" jdbcType="INTEGER" property="id" />
            <result column="name" jdbcType="VARCHAR" property="name" />
            <result column="area_id" jdbcType="INTEGER" property="areaId" />
            <result column="parent_id" jdbcType="INTEGER" property="parentId" />
        </collection>
    </collection>
    <!-- 使用columnPrefix简化书写,否则需要写成
    	<collection property="subAreas" ofType="cn.edu.ntu.entity.Area" >
	        <id column="bid" jdbcType="INTEGER" property="id" />
	        <result column="bname" jdbcType="VARCHAR" property="name" />
	        <result column="barea_id" jdbcType="INTEGER" property="areaId" />
	        <result column="bparent_id" jdbcType="INTEGER" property="parentId" />
	    </collection>
	     column的值与sql语句中的命名对应
     -->
  </resultMap>

  <!--因为是一对多的关系,用collection-->
  <select id="queryAllCity" resultMap="areasOther">
    select     
	    a.id, a.name, a.area_id, 
	    b.id bid, b.name bname, b.area_id barea_id,
        c.id cid, c.name cname, c.area_id carea_id
    from area a 
    left join area b on b.parent_id = a.area_id
    left join area c on c.parent_id = b.area_id
    where a.parent_id is null
  </select>

以上案例并没有成功,不知道是不是queryAllCity的sql语句书写问题,请大牛指点!

另一种支持多层嵌套的方式:

<!-- 同表级联查询 (支持多层嵌套) -->
  <resultMap type="cn.edu.ntu.entity.Area" id="areas">
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="area_id" jdbcType="INTEGER" property="areaId" />
    <result column="parent_id" jdbcType="INTEGER" property="parentId" />
    <collection property="subAreas" ofType="cn.edu.ntu.entity.Area" column="area_id" 
        select="queryCityByParentId">
        <id column="id" jdbcType="INTEGER" property="id" />
        <result column="name" jdbcType="VARCHAR" property="name" />
        <result column="area_id" jdbcType="INTEGER" property="areaId" />
        <result column="parent_id" jdbcType="INTEGER" property="parentId" />
    </collection>
  </resultMap>

  <!--因为是一对多的关系,用collection-->
  <select id="queryCityByParentId" parameterType="java.lang.Integer" resultMap="areas">
    select
    	a.id, a.name, a.area_id, a.parent_id 
    from area a where a.parent_id = #{area_id}
  </select>
  
  <!--因为是一对多的关系,用collection-->
  <select id="queryCity" resultMap="areas">
    select
    	a.id, a.name, a.area_id, a.parent_id  
    from area a where a.parent_id is null 
  </select>

以上方式在collection中将select指定的查询语句循环调用,查询条件为column的数据,最终将查询的结果放到property指定的属性中

执行结果:

源码路径:https://gitee.com/wpfc/websocket/blob/master/src/test/java/cn/dq/MybatisTest.java

参考:http://blog.csdn.net/u012485016/article/details/64500972

猜你喜欢

转载自my.oschina.net/u/2326864/blog/1622990