Mysql中使用树的设计
原来一直使用id与 parent_id结合的办法设计树,最近发现有些问题:
1、查询此结点下所有子结点的需求。
2、查询此结点上所有父结点的需求。
这些需求在oracle和sql server中可以使用一些办法在数据库端进行处理,但在mysql中处理就稍显麻烦,在sqlite中基本无解。所以想办法重新设计一下就显的很有必要的了。
添加两列:structure_node varchar(128)和 level int(11)
root 001
第一级第一个结点 001 001
第一级第二个结点 001 002
第二级第一个结点 001 001 001
这样查询起来就很方便了。
问题来了,
问题1:将现在id与parent_id的结构迁移到新结构上:
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.druid.DruidPlugin; public class Main { public static List<String> list_parent_id=new ArrayList<String>();
public static List<String> list_sql=new ArrayList<String>();
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
{
Properties prop = new Properties();
String classDir = Main.class.getResource("/").getPath();
FileInputStream fis = new FileInputStream(classDir+"/dsideal_config.properties");
prop.load(fis); // 配置druid数据库连接池插件
String driver =prop.getProperty("driverClass");
DruidPlugin druidPlugin = new DruidPlugin(prop.getProperty("jdbcUrl"), prop.getProperty("user"), prop.getProperty("password"), driver);
druidPlugin.start(); // 配置ActiveRecord插件
ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
arp.start(); String sql="select distinct scheme_id from t_resource_structure";
List<Record> scheme_list= Db.find(sql); for(int t=;t<scheme_list.size();t++)
{
list_parent_id.clear(); String scheme_id=scheme_list.get(t).get("scheme_id").toString();
//设置根
sql="update t_resource_structure set structure_node='001',level=1 where structure_id=?";
Db.update(sql,scheme_id); list_parent_id.add(scheme_id);
int level=;
while(list_parent_id.size()>)
{
level++;
update_node_byparent_id(level);
}
} System.out.println("结构转换成功完成!"); //提取新的映射关系到map里
Map<String,String> mymap=new HashMap<String,String>();
sql="select structure_id,structure_node from t_resource_structure";
List<Record> myr= Db.find(sql);
for(int i=;i<myr.size();i++)
{
mymap.put(myr.get(i).get("structure_id").toString(), myr.get(i).get("structure_node").toString());
}
//获取到资源表中的对应数据
sql="select resource_id,node_id from t_resource_base";
myr= Db.find(sql);
for(int i=;i<myr.size();i++)
{
list_sql.add("update t_resource_base set structure_node='"+mymap.get(myr.get(i).get("node_id"))+"' where resource_id='"+myr.get(i).get("resource_id")+"'");
}
System.out.println("正在提交资源的数据,请稍等...");
//事务提交
Db.batch(list_sql, ); System.out.println("所有操作成功完成!");
} private static void update_node_byparent_id(int level)
{
List<String> tmp_list_parent_id=new ArrayList<String>(); for( int k=;k<list_parent_id.size();k++)
{
System.out.println("正在处理,共"+list_parent_id.size()+"个,第"+(k+)+"个");
String sql="SELECT structure_id,parent_id FROM t_resource_structure where parent_id=? order by sort_id";
List<Record> mylist= Db.find(sql,list_parent_id.get(k)); for(int i=;i<mylist.size();i++)
{
tmp_list_parent_id.add(mylist.get(i).get("structure_id").toString()); int code=+(i+);
//父结点的node
sql="select structure_node from t_resource_structure where structure_id=?";
String parent_structure_node=Db.queryStr(sql,mylist.get(i).get("parent_id").toString());
String result_code=parent_structure_node+String.valueOf(code).substring(,);
sql="update t_resource_structure set structure_node='"+result_code+"',level="+level+" where structure_id='"+mylist.get(i).get("structure_id")+"'";
Db.update(sql);
}
}
list_parent_id.clear();
list_parent_id=tmp_list_parent_id;
}
}
2、有了structure_code没有structure_id和parent_id
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.druid.DruidPlugin; public class Main { /**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
{
Properties prop = new Properties();
String classDir = Main.class.getResource("/").getPath();
FileInputStream fis = new FileInputStream(classDir+"/dsideal_config.properties");
prop.load(fis); // 配置druid数据库连接池插件
String driver =prop.getProperty("driverClass");
DruidPlugin druidPlugin = new DruidPlugin(prop.getProperty("jdbcUrl"), prop.getProperty("user"), prop.getProperty("password"), driver);
druidPlugin.start(); // 配置ActiveRecord插件
ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
arp.start(); //要设置哪个结构
String scheme_id="5CA47D74-B745-4E09-A7B2-9E02DCB06DBF";
//处理一下根结点,根结点应该是有guid号 ,parent_id和structure_code的
String sql="update t_resource_structure set parent_id='11111111-1111-1111-1111-111111111111',level=1 where scheme_id=? and structure_node='001'";
Db.update(sql,scheme_id);
//保留结构ID和结构CODE两种方法
sql="select structure_id,structure_node from t_resource_structure where SCHEME_ID=? and parent_id is null";
List<Record> no_parent_list= Db.find(sql,scheme_id); Map<String,String> mymap=new HashMap<String,String>();
//放到Map里
for(int i=;i<no_parent_list.size();i++)
{
mymap.put(no_parent_list.get(i).get("structure_node").toString(), no_parent_list.get(i).get("structure_id").toString());
}
//循环取回来
List<String> list_sql=new ArrayList<String>();
for(int i=;i<no_parent_list.size();i++)
{
String code=no_parent_list.get(i).get("structure_node");
String id=no_parent_list.get(i).get("structure_id");
sql="update t_resource_structure set parent_id='"+mymap.get(code.substring(, code.length()-))+"' where structure_id='"+id+"'";
list_sql.add(sql);
}
if(list_sql.size()>)
{
Db.batch(list_sql, );
}
System.out.println("所有操作成功完成!");
} }
update t_resource_structure a inner join
(select structure_node,structure_id,scheme_id from t_resource_structure where scheme_id='F639942E-5211-4254-A3DF-E817A47C4D50') c
on a.scheme_id=c.scheme_id and SUBSTRING(a.structure_node,,LENGTH(a.structure_node)-)=c.structure_node
set a.parent_id=c.structure_id where a.scheme_id='F639942E-5211-4254-A3DF-E817A47C4D50' and LENGTH(a.structure_node)>
3、获取一个可用CODE的代码
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties; import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.druid.DruidPlugin; public class Main { public static List<String> list_parent_id=new ArrayList<String>();
public static List<String> list_sql=new ArrayList<String>();
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception
{
Properties prop = new Properties();
String classDir = Main.class.getResource("/").getPath();
FileInputStream fis = new FileInputStream(classDir+"/dsideal_config.properties");
prop.load(fis); // 配置druid数据库连接池插件
String driver =prop.getProperty("driverClass");
DruidPlugin druidPlugin = new DruidPlugin(prop.getProperty("jdbcUrl"), prop.getProperty("user"), prop.getProperty("password"), driver);
druidPlugin.start(); // 配置ActiveRecord插件
ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
arp.start();
String scheme_id="ED1695FB-6B6E-11E2-B11E-00FF2D04A858"; System.out.println(getNode(scheme_id,"")); System.out.println("所有操作成功完成!");
} /**
* 功能:传入一个父结点ID,获取这个结点下新生成一个子结点的可用ID
* 作者:黄海
* 时间:2013-07-22
* @param parent_node
* @return
* @throws Exception
*/
private static String getNode(String scheme_id,String parent_node) throws Exception
{
int level=parent_node.length()/+;
String result="";
String select_sql="select structure_node from t_resource_structure_copy where scheme_id=? and structure_node like ? and level="+level +" order by structure_node desc";
String sql=select_sql+" limit 1";
String structure_node=Db.queryStr(sql,scheme_id,parent_node+"%");
if(structure_node==null)
{
result=parent_node+"";
}
else
{
//后三位是啥
String last_three=structure_node.substring(structure_node.length()-, structure_node.length());
//如果没有到999就一直向后加1
if(Integer.parseInt(last_three)+<=)
{
result=parent_node+String.valueOf(+Integer.parseInt(last_three)+).substring(,);
}
else//如果到了999了,那么我们检查一下是不是前面有断号的,如果没有,那么就是超出了这个算法的极限,我们只支持一个结点下最多999个子节点
{
List<Record>mylist=Db.find(select_sql,scheme_id,parent_node+"%") ;
Map<String,String> mymap=new HashMap<String,String>();
for(int i=;i<mylist.size();i++)
{
last_three=mylist.get(i).getStr("structure_node").substring(mylist.get(i).getStr("structure_node").length()-, mylist.get(i).getStr("structure_node").length());
mymap.put(last_three,"");
}
boolean found=false; for(int i=;i<=;i++)
{
String key=String.valueOf(+i).substring(,);
if(mymap.get(key)!=null)
{
continue;
}
else
{
result=key;
found=true;
break;
}
}
if(!found) throw new Exception("不行啊,实在找不着可以用的号啊!");
}
}
return result;
} }
3、测试一下效率:
explain select * from t_resource_structure_copy force index(index_structure_node) where scheme_id='ED1695FB-6B6E-11E2-B11E-00FF2D04A858' and structure_node like '001001%'
强制使用了索引,这时执行效率如下:

查询时间为0.27秒查询出10000多条,也算可以了。
Mysql中使用树的设计的更多相关文章
- mysql中递归树状结构<转>
在Oracle 中我们知道有一个 Hierarchical Queries 通过CONNECT BY 我们可以方便的查了所有当前节点下的所有子节点.但很遗憾,在MySQL的目前版本中还没有对应的功能. ...
- MySQL中B+树索引的使用
1) 不同应用中B+树索引的使用 对于OLTP应用,由于数据量获取可能是其中一小部分,建立B+树索引是有异议时的 对OLAP应用,情况比较复杂,因为索引的添加应该是宏观的而不是微观的. ...
- mysql中有关树的函数
用mysql客户端在库中建立函数queryOrgChildren(查找子节点)和queryOrgLevel(查看当前节点在树中的级别):DROP FUNCTION IF EXISTS `queryOr ...
- Mysql中的sql是如何执行的 --- 极客时间学习笔记
MySQL中的SQL是如何执行的 MySQL是典型的C/S架构,也就是Client/Server架构,服务器端程序使用的mysqld.整体的MySQL流程如下图所示: MySQL是有三层组成: 连接层 ...
- 【数据库】Mysql中主键的几种表设计组合的实际应用效果
写在前面 前前后后忙忙碌碌,度过了新工作的三个月.博客许久未新,似乎对忙碌没有一点点防备.总结下来三个月不断的磨砺自己,努力从独乐乐转变到众乐乐,体会到不一样的是,连办公室的新玩意都能引起莫名的兴趣了 ...
- 面试官:为什么Mysql中Innodb的索引结构采取B+树?
前言 如果面试官问的是,为什么Mysql中Innodb的索引结构采取B+树?这个问题时,给自己留一条后路,不要把B树喷的一文不值.因为网上有些答案是说,B树不适合做文件存储系统的索引结构.如果按照那种 ...
- 一、MySQL中的索引 二、MySQL中的函数 三、MySQL数据库的备份和恢复 四、数据库设计和优化(重点)
一.MySQL中的索引###<1>索引的概念 索引就是一种数据结构(高效获取数据),在mysql中以文件的方式存在.存储建立了索引列的地址或者指向. 文件 :(以某种数据 结构存放) 存放 ...
- 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效
数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...
- mysql status关键字 数据表设计中慎重使用
mysql status关键字 数据表设计中慎重使用
随机推荐
- ASP.NET Web API 帮助(help)页面上没有 Test API按钮的解决方法
参与一个web API项目时发现它的help页面特别好用,不仅可以根据webapi的方法和注释自动生成帮助文档以方便查阅,还可以在这个页面上测试webapi方法.于是在自己新建项目时也打算将这个hel ...
- 把php.exe加入系统环境变量-使用命令行可快速执行PHP命令
有时候在执行长时间运行的脚本程序的时候,浏览器是架不住的.我们就可以使用CMD命令行或者LINUX命令行执行PHP程序 1.把PHP.EXE加入到环境变量,不用每次都进入到PHP的目录 ① 右击我的 ...
- lookupedit清空选择 z
lookupedit绑定数据,选择以后.怎么点击按钮使lookupedit回到初始位置,即nulltext的值.注意,是点击按钮,不是按默认的CTRL+DELETE. txtKHXX.EditValu ...
- 一个强大的LogParser的UI工具--logparserlizard简介
日志分析,特别是IIS日志,一般人都会想到LogParser工具,的确很强.但是命令行的操作界面令很多非专业的管理人员望而生畏,现在好了,有一个可视化的LogParser的UI工具可以使用了! Log ...
- Delphi 保存写字板程序, 并进行打印
wDoc := docapp1.Documents.open(ExtractFilePath(Paramstr(0)) + 'abc.doc'); wDoc.SaveAs(ExtractFilePat ...
- [转]Chrome浏览器的离线安装包下载地址
每当chrome有更新之后,都有不少用户想要下载离线版的安装文件,但苦于找不到下载地址而发愁,其实这个问题很简单,下面我来分享一下方法(仅针对Windows操作系统): 对于稳定版(正式版)Chrom ...
- 一起刷LeetCode5-Longest Palindromic Substring
发现自己原来掌握的一下算法,都忘掉了,啊啊啊 ----------------------------------------------------------------------------- ...
- 使用Maven将Hadoop2.2.0源码编译成Eclipse项目
编译环境: OS:RHEL 6.3 x64 Maven:3.2.1 Eclipse:Juno SR2 Linux x64 libprotoc:2.5.0 JDK:1.7.0_51 x64 步骤: 1. ...
- 第二百三十二天 how can I 坚持
早上竟然飘起了大学,可是就下了一会,没有一点学的痕迹. 博客园真不知道怎么回事了,字真的好小了. 晚上回来心情好不好,感觉好累,最近不知道怎么了,约罗娜出来吃个饭怎么都约不出来,咋办呢.哎,愁人. 最 ...
- c++builder 代码输入助手
c++builder 代码输入助手 指针箭头.指针符号-> 输入太麻烦 java.c#.delphi 语音,输入. 一个字符,就可以弹出代码提示窗口.很是方便. c++,输入->,需要按3 ...