1、ExecuteNonQuery;ExecuteScalar;ExecuteQuery;
2、什么是SQL注入漏洞?怎么避免。
3、DataSet、DataTable、DataRow的关系是什么?DataSet和DataReader的区别是什么?
4、编写一个MySqlHelper;
5、什么是事务?
6、使用MySqlHelper实现增删改查。
7、ADO.Net连接SQLServer
------------------------------------------------
第 1 节 ADO.Net简介
ADO.Net是.Net中提供的标准访问数据库的接口,访问不同的DBMS的底层方法是不一样的,ADO.Net把访问数据库方法进行了统一,访问MYSQL,Oracle,SQLServer等不同的数据库的用法几乎一模一样。
ADO.Net是规范,被不同的数据库厂商提供ADO.Net的实现,称之为ADO.Net驱动,每个厂商提供的驱动可以用来操作自己的数据库。
MYSQL的.Net驱动mysql-connector-net-***.msi下载地址:
1)http://www.cncrk.com/downinfo/41149.html
2)http://www.cr173.com/soft/50789.html
3)http://dev.mysql.com/downloads/file.php?id=405442
4)http://download.csdn.net/detail/du_niao/6500785
新建项目,添加引用→“扩展”,添加Mysql.Data;如果是直接解压版,然后直接添加对MySql.Data.dll文件的引用;
using (MySqlConnection conn =
new MySqlConnection("Server=localhost;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand()) { conn.Open();//一定要在执行前Open数据库连接 cmd.CommandText = "Insert into T_Users(UserName,Password) values('中国人','123')"; int rowCount = cmd.ExecuteNonQuery(); Console.WriteLine("受影响的行数"+rowCount); }
解释一下代码:
MySqlConnection、MySqlCommand实现了IDisposable接口,因此使用using进行资源释放;
"Server=localhost;Database=study1;uid=root;pwd=root;Charset=utf8"叫连接字符串,Server是Mysql服务器的地址,Database是连接的数据库,uid、pwd是用户名和密码,采用utf8编码。
conn.Open():在执行MySqlCommand之前一定要先打开数据库连接,否则会报错。
ExecuteNonQuery是执行Update、Insert、Delete等非查询语句,返回值为受影响的行数。
------------------------------------------------
第 2 节 执行Insert语句
ExecuteNonQuery是执行Update、Insert、Delete等非查询语句,返回值为受影响的行数。
------------------------------------------------
第 3 节 ExecuteScalar()
ExecuteScalar:执行查询,并返回查询所返回的结果集中第一行的第一列,忽略其他行列。一般用来简单的获得只有一行一列的查询结果的值。聚合函数
案例1:
cmd.CommandText = "Select count(*) from T_Users";
long count = (long)cmd.ExecuteScalar();
案例2:
cmd.CommandText = "Select Password from T_Users where UserName='admin'";
string pwd = (string)cmd.ExecuteScalar();
if (string.IsNullOrEmpty(pwd))
{
Console.WriteLine("找不到admin");
}
else
{
Console.WriteLine("admin的密码:" + pwd);
}
------------------------------------------------
第 4 节 ExecuteReader
cmd.CommandText = "select * from T_Users";
using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { long id = reader.GetInt64("Id"); string userName = reader.GetString("UserName"); string password = reader.GetString("Password"); Console.WriteLine("id=" + id + ";UserName=" + userName + ";Password=" + password); } }
注意:Reader的遍历、读取时需要Connection保持连接,如果关闭了Connection,使用Reader会出错。
也可以根据列序号获取列的值,效率略高,不过程序不容易读;通过reader.GetOrdinal("Age")获得列名对应的列序号。
------------------------------------------------
第 5 节 SQL注入漏洞说明
a' or 'a' ='a
------------------------------------------------
第 6 节 参数化查询1
为什么这样就不会有“SQL注入漏洞”?
参数化查询优点:安全;效率高(SQL预编译)
陷阱:
不要用MySqlParParameter(string ParameterName,object value)的这个函数,因为("Age",0)会被匹配成MySqlParameter(string ParameterName,MySqlDbType dbType)这个构造函数。
------------------------------------------------
第 7 节 参数化查询2
/* using(MySqlConnection conn = new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8")) using (MySqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = "Insert into @p(UserName,Password) values(@un,@pwd)"; cmd.Parameters.Add(new MySqlParameter { ParameterName = "@p", Value = "t_users" }); cmd.Parameters.Add(new MySqlParameter { ParameterName="@un",Value="rupeng"}); cmd.Parameters.Add(new MySqlParameter { ParameterName="@pwd",Value="123456"}); cmd.ExecuteNonQuery(); }*/ /* using(MySqlConnection conn = new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8")) using (MySqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = "Insert into T_Users(UserName,Password,Age) values(@un,@pwd,@Age)"; cmd.Parameters.Add(new MySqlParameter("@un","test1")); cmd.Parameters.Add(new MySqlParameter("@pwd", "321")); //int i = 0; //cmd.Parameters.Add(new MySqlParameter("@Age", i)); // cmd.Parameters.Add(new MySqlParameter("@Age", 0)); cmd.Parameters.Add(new MySqlParameter("@Age",(object)0)); cmd.ExecuteNonQuery(); }*/
关键字,表名,字段名等是不能用参数化进行替。
编译器重载匹配
int i=0; 调用i //
(object)0 //常量
------------------------------------------------
第 8 节 读取数据库中的null值
使用IsDBNull获取指定序号的列的值是否为null
int? age=null;
if (!reader.IsDBNull(reader.GetOrdinal("Age")))
{
age = reader.GetInt32("Age");
}
using (MySqlConnection conn =
new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8"))
using (MySqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = "select * from T_Users;"; using (MySqlDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { string username = reader.GetString("UserName"); // string password = reader.GetString("Password"); string password; if (reader.IsDBNull(reader.GetOrdinal("Password"))) { password = null; } else { //GetString/GetInt32 无法读取数据库中的null值 //需要提前用IsDBNull判断 password = reader.GetString("Password"); } int? age; if (reader.IsDBNull(reader.GetOrdinal("Age"))) { age = null; } else { age = reader.GetInt32("Age"); } // int age = reader.GetInt32("Age"); Console.WriteLine("用户名:"+username+";密码:"+ (password==null?"不知道密码":password)+";年龄:"+ (age==null?"不知道年龄":age.ToString())); } } }
reader.GetString/GetInt32无法读取字段值为null的数据,需要使用reader.IsDBNull(reader.GetOrdinal("Password"))先进行判断。
------------------------------------------------
第 9 节 离线结果集入门
DataReader是服务器结果集游标的体现,所有查询出来的数据都在MySQL服务器上。好处是:当查询结果数据量大的时候避免占用本地内存。不过大部分项目中都会避免大查询结果,
因此缺点就明显了:
读取的时候必须保持Connection,
不仅用起来麻烦,而且会较长时间占用MySQL服务器的连接资源。
DataSet是一个离线结果集容器,它把结果数据放到本地内存中。因为查询结果可能会包含多个表,因此DataSet包含若干DataTable(ds.Tables)、DataTable包含若干DataRow(dt. Rows)。
用法1:
DataSet ds = new DataSet();
MySqlDataAdapter adapter = new MySqlDataAdapter(cmd); adapter.Fill(ds); DataTable table = ds.Tables[0];
DataSet 可以盛放多个查询结果集到DataTable ;DataAdapter还可以对结果进行傻瓜化更新、删除、修改。我们一般查询结果集就一个DataTable, DataAdapter的傻瓜化更新不适合于正式的项目,因此有更简单的用法
DataTable dt = new DataTable();
dt.Load(reader);
把DataTable声明到using外,using外再使用查询结果。
遍历DataTable:
for (int i = 0; i < dt.Rows.Count; i++)
{
DataRow row = dt.Rows[i]; string name = row.IsNull("Name")?null:(string)row["Name"];//NULL处理 Console.WriteLine("name"+name); }
案例代码:
/* using (MySqlConnection conn = new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8")) using (MySqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = "select * from t_users"; using (MySqlDataReader reader = cmd.ExecuteReader()) { DataTable dt = new DataTable(); dt.Load(reader); for (int i = 0; i < dt.Rows.Count; i++) { DataRow row = dt.Rows[i]; int id = (int)row["Id"];//下标方式获得是object string username = (string)row["UserName"]; //做很复杂的io操作,把username存到文件中 //这样就会长期占据Connection // object obj = row["Password"]; //if(row["Password"]==DBNull.Value)//返回的不是null,而是DBNull //string password = (string)row["Password"]; //int age = (int)row["Age"]; string password = row.IsNull("Password") ? null : (string)row["Password"]; int? age = row.IsNull("Age") ? (int?)null : (int)row["Age"]; Console.WriteLine("id=" + id + ";Username=" + username +";username="+username+";age="+age); } } }*/ /* DataTable table = new DataTable(); using (MySqlConnection conn = new MySqlConnection("Server=127.0.0.1;Database=study1;uid=root;pwd=root;Charset=utf8")) using (MySqlCommand cmd = conn.CreateCommand()) { conn.Open(); cmd.CommandText = "select * from t_users"; using (MySqlDataReader reader = cmd.ExecuteReader()) { table.Load(reader);//加载到table中 } } for (int i = 0; i < table.Rows.Count; i++) { DataRow row = table.Rows[i]; int id = (int)row["id"]; string username = (string)row["UserName"]; Console.WriteLine(id+":"+username); } */
------------------------------------------------
第 10 节 离线结果集要注意的问题
row.IsNull("Password") 或 row["Password"] == DBNull.Value
数据库连接不能长期占用。读完数据就关闭。别的代码在外面。
------------------------------------------------
第 11 节 MySqlHelper需求分析
1.AD.Net的连接字符串写到配置文件中。
2.每次操作数据库都要写一大堆代码,太麻烦,需要封装一个简化的ADO.Net操作的库出来:
配置文件中设置连接字符串;
简化连接的创建;
简化SQL的执行。
3.如果一个操作要执行多条SQL语句,如果每条都打开一次连接->执行->关闭连接的话,效率非常低,而且会有“事务”的问题。因此应该提供“打开、执行、关闭”这样的方法,也要提供“使用现有连接执行”的方法。
4.参数代查询的查询参数个数是不确定的,用可变长度参数会更方便。
5.为了方便大部分情况下的小结果集,执行查询返回DataTable。
MySqlHelper方法规划:
public static MySqlConnection CreateConnection();//得到已经打开的连接
//1.读取配置文件
//2.创建连接
//3.打开连接
public static int ExectueNonQuery(MySqlConnection conn, string sql, params MySqlParameter[] parameters);
public static int ExectueNonQuery( string sql, params MySqlParameter[] parameters);
//1.
public static object ExecuteScalar(MySqlConnection conn, string sql, params MySqlParameter[] parameters);
public static object ExecuteScalar(string sql, params MySqlParameter[] parameters);
public static DataTable ExecuteQuery(MySqlConnection conn, string sql, params MySqlParameter[] parameters);
public static DataTable ExecuteQuery( string sql, params MySqlParameter[] parameters);
------------------------------------------------
第 12 节 实现MysqlHelper
连接字符串一般配置到App.config(网站是Web.config)中的<connectionStrings>段中
使用ConfigurationManager类(添加对System.Configuration的引用)读取
string connstr =
ConfigurationManager.ConnectionStrings["connstr"].ConnectionString
注意:
1、注意不要修改App.config的名字为App1.config之类的,必须叫App.config(网站是Web.config)
2、一定要保证代码中的名字和配置文件中的名字一致(初学者容易犯错的,一般提示“初始化代码错误”这个错误就是因为两者名字不一致造成的)
using MySql.Data.MySqlClient;
using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ADONETTest2 { class MySqlHelper { private static readonly string connstr = ConfigurationManager.ConnectionStrings["connstr"].ConnectionString; public static MySqlConnection CreateConnection() { //using (MySqlConnection conn = new MySqlConnection(connstr)) MySqlConnection conn = new MySqlConnection(connstr); conn.Open(); return conn; } public static int ExecuteNonQuery(MySqlConnection conn, string sql, params MySqlParameter[] parameters) { using (MySqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = sql; /* foreach (MySqlParameter p in parameters) { cmd.Parameters.Add(p); }*/ cmd.Parameters.AddRange(parameters); return cmd.ExecuteNonQuery(); } } public static int ExecuteNonQuery(string sql, params MySqlParameter[] parameters) { using (MySqlConnection conn = CreateConnection()) { return ExecuteNonQuery(conn, sql, parameters); } } public static object ExecuteScalar(MySqlConnection conn, string sql, params MySqlParameter[] parameters) { using (MySqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = sql; cmd.Parameters.AddRange(parameters); return cmd.ExecuteScalar(); } } public static object ExecuteScalar(string sql, params MySqlParameter[] parameters) { using (MySqlConnection conn = CreateConnection()) { return ExecuteScalar(conn, sql, parameters); } } public static DataTable ExecuteQuery(MySqlConnection conn, string sql, params MySqlParameter[] parameters) { DataTable table = new DataTable(); using (MySqlCommand cmd = conn.CreateCommand()) { cmd.CommandText = sql; cmd.Parameters.AddRange(parameters); using (MySqlDataReader reader = cmd.ExecuteReader()) { table.Load(reader); } } return table; } public static DataTable ExecuteQuery(string sql, params MySqlParameter[] parameters) { using (MySqlConnection conn = CreateConnection()) { return ExecuteQuery(conn, sql, parameters); } } } }
------------------------------------------------
第 13 节 获得自动增长字段的值
1、使用LAST_INSERT_ID()获取“最后一次插入的自动递增列的值”
2、需要注意Insert语句和select LAST_INSERT_ID()一定要在要在同一个连接中。
using (MySqlConnection conn = MySqlHelper.CreateConnection())
{
MySqlHelper.ExecuteNonQuery(conn,
"insert into t_users(UserName,Password) values('我几时我','123')"); object o = MySqlHelper.ExecuteScalar(conn, "select Last_Insert_Id()"); //Last_Insert_Id()是获取当前连接中,最近一次自动递增字段的值 ulong id = (ulong)o;//无符号的long Console.WriteLine(id); }
可以Insert、LAST_INSERT_ID()在同一个连接中单独执行,也可以把LAST_INSERT_ID()放到insert语句后面用;分割(使用ExecuteScalar执行即可)
ulong id = (ulong)MySqlHelper.ExecuteScalar("insert into t_users(UserName,Password) values('我几时我','123');select last_insert_id()");
Console.WriteLine(id);
------------------------------------------------
第 14 节 事务的原子性
事务(Transaction)有四大特征:原子性,一致性,隔离性,持久性。
原子性:“几个操作要么都成功,要么都失败”!
事务的几个关键环节:
1)要在一个连接中;
2)启动事务:MySqlTransaction tx = conn.BeginTransaction();
3)操作结束后执行tx.Commit() 提交事务;
4)如果执行出错,则tx.Rollback()回滚(当前事务的操作全部取消)。
MySqlTransaction tx = conn.BeginTransaction();
try { MySqlHelper.ExecuteNonQuery(conn, "Update t_accounts Set Amount=Amount-1000 where Number='0001'"); string s = null; s.ToLower(); MySqlHelper.ExecuteNonQuery(conn, "Update t_accounts Set Amount=Amount+1000 where Number='0002'"); tx.Commit(); } catch (Exception ex) { tx.Rollback(); }
注意:必须是同一个连接,创建后,还得使用创建的连接执行SQL语句!每个MySqlHelper.Excute的方法必须使用创建的连接conn。
using (MySqlConnection conn = MySqlHelper.CreateConnection())
using(MySqlTransaction tx=conn.BeginTransaction( )) { try { //必须是同一个连接conn不能忘 ulong id = (ulong)MySqlHelper.ExcuteScalar(conn,"Insert into T_Users (UserName,Password)values(@UserName,@Password);select LAST_INSERT_ID()", new MySqlParameter { ParameterName = "@UserName", Value = "test" }, new MySqlParameter { ParameterName = "@Password", Value = "aaaa" }); Console.WriteLine(id); string str = null; str.ToLower(); MySqlHelper.ExcuteNonQuery(conn, "update T_users set UserName='bbbb' where Id=10257");//必须是同一个连接conn不能忘 tx.Commit(); } catch (Exception ex) { tx.Rollback(); } }
------------------------------------------------
第 15 节 手机号码归属地:导入数据
手机号码归属地数据库.zip 下载地址:
1、下载地址1:http://pan.baidu.com/s/1eQETGqQ 密码:pcq7
2、下载地址2:手机号码归属地和身份证归属地数据库.zip
http://static.rupeng.com/upload/images/20156/BB642F2DB1F19FFB5714198BA5953E69%E6%89%8B%E6%9C%BA%E5%8F%B7%E7%A0%81%E5%BD%92%E5%B1%9E%E5%9C%B0%E5%92%8C%E8%BA%AB%E4%BB%BD%E8%AF%81%E5%BD%92%E5%B1%9E%E5%9C%B0%E6%95%B0%E6%8D%AE%E5%BA%93.zip
项目地址:http://static.rupeng.com/upload/images/201412/AAD80266B1CD5A14E4E8B0B3C3B47F32PhoneNunArea.zip
有的学生导入数据后发现“数据库怎么只导入了1000条”,其实不是只导入了1000条,而是全部导入的,只是navicat是分页显示的,看右下角,可以翻页的。
------------------------------------------------
第 16 节 手机号码归属地的查询以及作业说明
身份证归属地数据库.zip 下载地址: 身份证所在地.zip
项目代码下载地址:PhoneNunArea.zip
练习:
写一个身份证所在地查询的程序。
------------------------------------------------
第 17 节 CRUD案例之需求说明及数据查询
人员的增删改查
CRUD:增加(Create),读取(Retrieve),更新(Update),删除(Delete)
(*)DataGridView的使用:把DataTable赋值给DataGridView的DataSource属性,会自动填充,不过列名都是英文,因此通过代码设置AutoGenerateColumns属性为false,然后手动增加列。列设定DataPropertyName为要显示的属性的名字,HeaderText为表头显示的文本。勾掉启用删除,启用添加,启用编辑。
(*)增加"编辑","删除"两个列:增加“DatagridviewlinkColumn”类型的列,Text设定为"编辑"/"删除",UserColumntextForLinkValue为true,这样就把Text显示到单元格中了,否则会尝试取控件的属性,就空白了。
------------------------------------------------
第 18 节 CRUD案例之删除以及mysq的if函数
案例:增删改查
(*)删除点击的行:响应CellContentClick事件,e.ColumnIndex获得列号,e.RowIndex获得行号。然后:DataTable dt=(DataTable)grid.DataSource;
DataRow=dt.Rows[e.RowIndex];
删除之前提示一下用户,删除后刷新数据。
性别显示为“0,1”,不好看,使用mysql的函数if:If(Gender,'男','女') Gender,mysql还有case、日期函数、字符串函数等。
------------------------------------------------
第 19 节 CRUD案例之编辑的加载
------------------------------------------------
第 20 节 CRUD案例之新增和编辑保存
项目代码下载:CRUDTest1.zip
------------------------------------------------
第 21 节 SQLServer2008R2的安装
SQLServer 2008 R2下载:
1)下载地址1:http://www.pc6.com/softview/softview_20580.html
注意:
1、SQLServer 2008 R2是SQLServer 2008的升级版,SQLServer 2008在Win7下有兼容性问题,不能运行,需要打补丁才可以。所以推荐大家装“SQLServer 2008 R2”,而不是装“SQLServer 2008”
2、大家在安装SQLServer的时候,如果跟着老师的操作安装下来还是装不上,比如如下图
如果跟同学以及学习辅导老师确认不是安装步骤的问题的话,那么很有可能是因为你使用了修改版的Windows系统(比如雨林木风、深度、电脑公司、萝卜花园等),这些修改版的Windows系统中可能一些关键性的系统组件被阉割掉了,造成SQLServer等组件安装失败。因此建议大家安装微软的原版系统。
3、大家用SQLServre 2005也可以,对于初学者来讲没什么差别。但是不建议大家安装SQLServer 2012、SQLServer 2014等新的版本,因为操作会和咱们讲课时候不一致。有同学会问了“不用新系统我们不就过时了吗”,我的回答:这些新版本的SQLServer的高级特性做为初学者来讲用不到,所以装上新版本装上只能“装B”用,其实学习时用的还是基础的功能,何苦呢。
4、据有同学说“SQLServer 2008 R2”在Windows 10等新系统中同样有兼容性问题,而且暂时没有解决方案。因此强烈建议各位同学不要用Windows8、Windows 10等新操作系统。这种新的操作系统出来时间不久,很多软件兼容性还不好,会浪费大家太多的时间在环境的配置、重装上,还是用Windows 7这样稳定的操作系统,节省出宝贵的时间用来学习会更好。
------------------------------------------------
第 22 节 SQLServerManagementStudio的使用
mssql:bigit:long
mysql:long:long
mssql:varchar(没有中文);nvarchar(可能有中文)
mysql:varchar
nvarchar(MAX) GB
mssql:top (select top 20)
mysql:limit;
mssql:自动递增
mysql:是标识
保存表设计修改的时候,如果提示“不允许保存更改”:工具→选项→Designers→"阻止保存要求重新创建表的更改"。
遇到报错信息,先仔细阅读错误提示信息。
------------------------------------------------
第 23 节 ADO.Net连接SQLServer(SoEasy)
1、ADO.Net如何连接SQLServer:SQLServer驱动.Net内置(亲生的);把MySqlConnection换成SqlConnection,MySql***换成Sql***。
2、连接字符串:
server=ip;user id=sa;password=密码;database=db1
3、SQLHelper:把MySql查找替换成Sql就可以了。
4、获得自动增长列的值:Insert into t1(...) output inserted.Id values(.........)
5、(*)如果基于接口编程,只要改动CreateConnection就可以(查询参数以Dictionary<string,object>传递;如果使用Provider,连代码都不用改,改配置文件即可。
6、需要特别注意:SqlServer的事务和mysql事务使用有一点不一样的地方是“需要把BeginTransaction返回的SqlTransaction对象赋值给SqlCommand的Transaction属性”
------------------------------------------------
第 24 节 通过接口编程使用ADO.Net感受多态的强大
学完本节课后开始进行自测环节,自测完成后会组织班级讨论。题目如下:
第一题:
表一:学生表 t_student
主键Id |
姓名Name |
性别Gender |
出生年月BirthDay |
家庭住址Address |
备注Remarks |
1 |
张三 |
男 |
1981-8-9 |
北京 |
NULL |
表二:课程表t_course
主键Id |
课程名称Name |
学分Score |
1 |
计算机基础 |
2 |
2 |
C语言 |
2 |
表三:成绩表 t_grade
学生主键StudentId |
课程主键CourseId |
分数Score |
1 |
1 |
80 |
1 |
2 |
90 |
题目:编写SQL语句完成下面的功能:
条件查询:
1) 在t_grade表中查找80-90分的学生Id和分数
2) 在t_grade表中查找课程Id为3学生的平均分
3) 在t_grade表中查询学习各门课程的人数
4) 查询所有姓张的学生的学号和姓名
5) 查询分数在80-90分的学生的学号、姓名、分数
6) 查询学习了’C语言’课程的学生学号、姓名和分数
第二题
不参考、不对照任何老师、同学的代码编写连接SQLServer数据库的SQLHelper。并记录写完需要的时间。
第三题
编写通讯录管理软件,有联系人列表界面、联系人新增/修改界面、还可以删除联系人。联系人有如下信息:姓名、性别、生日、手机、邮箱、通讯地址。
在“联系人列表”界面中,点击工具栏中的“导出”按钮,会弹出保存文件对话框,用户选择一个文件后,可以将所有的联系人导出到文本文件。每一行是一个联系人信息,每一行的信息为:姓名、性别、生日、手机、邮箱,各列之间用“|”分割,比如
张三|男|1992-03-05|13888888888|[email protected]
李四|女|1995-12-12|13999999999|[email protected]
分别用SQLServer和MYSQL实现两个版本,并不能互相拷贝代码。并记录写完两个版本各需要的时间。
第四题
用SQLServer重写手机号码查询归属地案例。并记录写完需要的时间。
------------------------------------------------
如鹏网:http://www.rupeng.com