SQLSever视图和存储过程

一.视图(View)

1. 为什么要学习视图?

在没有视图之前,我们都是写各种各样的SQL语句,有点,非常灵活。后面我们学习应用程序开发的时候,通过C#发送过来的SQL语句

到达数据库的时候,会执行什么过程呢?

数据库接收到各种应用程序发送的SQL语句的时候,通常的流程是这样的:

【1】语法检查-->【2】优化(根据你的查询条件内容,和索引情况等,综合优化一下)-->【3】编译-->【4】执行

我们想,常见的查询,尤其是组合查询,能不能把查询固化到数据库服务器端,然后客户端使用的时候,只是调用一下呢?

当然可以,这个就是我们要学习的存储过程和视图。

视图其实就是一个查询,本身没有数据,就是把我们要查询的SQL语句,经过优化后经过编译存储到数据库服务器端。

视图我们本身也可以把它看成一个“没有数据的表”。

2.视图的创建与使用。这里提前创建了一个CourseManageDB数据库

use CourseManageDB
go
--普通查询
select CourseId,CourseName,CourseContent,ClassHour,Credit,Course.CategoryId from Course inner join CourseCategory on Course.CategoryId=CourseCategory.CategoryId;
--把上述查询添加到视图中
if exists(select * from sysobjects where name=queryCourseInfo_view)
drop view queryCourseInfo_view
go
--创建视图
create view queryCourseInfo_view
as
select CourseId,CourseName,CourseContent,ClassHour,Credit,Course.CategoryId from Course inner join CourseCategory on Course.CategoryId=CourseCategory.CategoryId;
go
--视图创建好后,我们可以把它看成表一样查询
select * from queryCourseInfo_view where CourseId>1005;
--实际开发中,可能会比较复杂:case when 
--创建一个复杂的视图
if exists(select * from sysobjects where name=queryCourseInfo_view2)
drop view queryCourseInfo_view2
go
create view queryCourseInfo_view2
as 
  select Course.CategoryId,CourseId,CourseName,CourseContent,Credit,TeacherId,CategoryName,ClassHour=case
      when ClassHour>400 then 500
      when ClassHour<400 then 400
      else
      300
      end
  from Course inner join CourseCategory 
  on Course.CategoryId=CourseCategory.CategoryId; 
go
--使用视图
select * from queryCourseInfo_view2;

在C#中调用视图,视图的查询和查询表一样,把表名换成视图名称即可。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Models;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;

namespace DAL
{
    /// <summary>
    /// 通用数据访问类
    /// </summary>
    [Serializable]
    public class SQLHelper
    {
        private static string connString = ConfigurationManager.ConnectionStrings["connString"].ToString();
        /// <summary>
        /// 通用增删改方法
        /// </summary>
        /// <param name="cmdText">查询语句</param>
        /// <param name="param">参数数组</param>
        /// <param name="IsProcedure">判断是否是存储过程</param>
        /// <returns>返回受影响的行数</returns>
        public static int Update(string cmdText, SqlParameter[] param = null, bool IsProcedure = false)
        {
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(cmdText, conn);
            try
            {
                conn.Open();
                if (param != null)
                {
                    cmd.Parameters.AddRange(param);
                }
                if (IsProcedure == true)
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                }
                return cmd.ExecuteNonQuery();
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                conn.Close();
            }
        }


        /// <summary>
        /// 启用事务来执行多条sql语句
        /// </summary>
        /// <param name="listSql"></param>
        /// <returns></returns>
        public static bool UpdateByTrans(List<string> listSql)
        {
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = conn;
            try
            {
                conn.Open();
                cmd.Transaction = conn.BeginTransaction();//开启事务
                foreach (string sql in listSql)
                {
                    cmd.CommandText = sql;
                    cmd.ExecuteNonQuery();
                }
                cmd.Transaction.Commit();//提交事务(提交后会自动清除事务)
                return true;
            }
            catch (Exception ex)
            {
                if (cmd.Transaction != null)
                    cmd.Transaction.Rollback();//执行某一条sql语句时出错,回滚事务(回滚事务后会自动清除事务)
                cmd.Transaction = null;//清楚事务
                throw ex;
            }
            finally
            {
                //为了以防万一,最后加一条判断,清除事务
                if (cmd.Transaction != null)
                    cmd.Transaction = null;
                conn.Close();
            }

        }


        /// <summary>
        ///查询单条数据
        /// </summary>
        /// <param name="cmdText">查询语句</param>
        /// <param name="param">参数数组</param>
        /// <param name="IsProcedure">判断是否是存储过程</param>
        /// <returns>返回单条数据查询结果</returns>
        public static object GetSingleResult(string cmdText, SqlParameter[] param = null, bool IsProcedure = false)
        {
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(cmdText, conn);
            try
            {
                conn.Open();
                if (param != null)
                {
                    cmd.Parameters.AddRange(param);
                }
                if (IsProcedure == true)
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                }
                return cmd.ExecuteScalar();//可以执行一个增删改语句的同时再执行一个查询语句(比如添加,再查询添加的标识列)
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                conn.Close();
            }
        }

        /// <summary>
        ///返回查询结果集
        /// </summary>
        /// <param name="cmdText">查询语句</param>
        /// <param name="param">参数数组</param>
        /// <param name="IsProcedure">判断是否是存储过程</param>
        /// <returns>返回查询结果集</returns>
        public static SqlDataReader GetReader(string cmdText, SqlParameter[] param = null, bool IsProcedure = false)
        {
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(cmdText, conn);
            try
            {
                conn.Open();
                if (param != null)
                {
                    cmd.Parameters.AddRange(param);
                }
                if (IsProcedure == true)
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                }
                return cmd.ExecuteReader(CommandBehavior.CloseConnection);//reader关闭,conn也将关闭(conn关闭,reader将读取不到数据,会报错)
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 基于DataSet来实现数据的查询(视图的操作类似于表)
        /// </summary>
        /// <param name="cmdText">查询语句或者存储过程</param>
        /// <param name="param">参数数组</param>
        /// <param name="IsProCedure">是否是存储过程</param>
        /// <param name="tableName">给表起的名</param>
        /// <returns>返回查询到的表数据</returns>
        public static DataSet GetTableData(string cmdText, bool IsProCedure = false, string tableName = null, SqlParameter[] param = null)
        {
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(cmdText, conn);
            try
            {
                conn.Open();
                if (param != null)
                {
                    cmd.Parameters.AddRange(param);
                }
                if (IsProCedure == true)
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                }
                //创建数据适配器
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                //创建数据集对象
                DataSet ds = new DataSet();
                if (tableName != null)
                {
                    da.Fill(ds, tableName);
                }
                else
                {
                    da.Fill(ds);
                }
                return ds;
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// 获取系统时间
        /// </summary>
        /// <returns></returns>
        public static DateTime GetTime()
        {
            return Convert.ToDateTime(SQLHelper.GetSingleResult("select getdate()"));
        }
    }
}

 

        /// <summary>
        /// 基于DataSet来实现数据的查询(视图的操作类似于表)
        /// </summary>
        /// <param name="cmdText">查询语句或者存储过程</param>
        /// <param name="param">参数数组</param>
        /// <param name="IsProCedure">是否是存储过程</param>
        /// <param name="tableName">给表起的名</param>
        /// <returns>返回查询到的表数据</returns>
        public static DataSet GetTableData(string cmdText, bool IsProCedure = false, string tableName = null, SqlParameter[] param = null)
        {
            SqlConnection conn = new SqlConnection(connString);
            SqlCommand cmd = new SqlCommand(cmdText, conn);
            try
            {
                conn.Open();
                if (param != null)
                {
                    cmd.Parameters.AddRange(param);
                }
                if (IsProCedure == true)
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                }
                //创建数据适配器
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                //创建数据集对象
                DataSet ds = new DataSet();
                if (tableName != null)
                {
                    da.Fill(ds, tableName);
                }
                else
                {
                    da.Fill(ds);
                }
                return ds;
            }
            catch (Exception)
            {
                throw;
            }
        }
        /// <summary>
        /// 通过存储过程来查询班级或者全校成绩
        /// </summary>
        /// <param name="tableName">表名</param>
        /// <returns></returns>
        public DataSet GetScoreList(string tableName = null)
        {
            //视图可以看成一张表,直接像sql语句一样用,直接查询
            string cmdText = "select * from view_GetScoreList";
            return SQLHelper.GetTableData(cmdText,false,tableName);
        }

3. 视图和普通的SQL语句查询比较

【1】视图本身就是一个提前写好的查询。但是这个查询保存到数据库服务器端。应用程序通过调用可以直接执行。

【2】普通的SQL语句查询。它在应用程序端。要执行,需要通过程序把SQL语句发送到数据库服务器端。

【3】后期的查询维护不同。如果我们要通过应用程序发送SQL语句,你必须要修改程序。但是如果我们使用视图呢?

可以适当的直接在数据库服务器上修改。

4. 视图本身的特点:本身不保存任何数据,只是保存到服务器端的一段编译好的SQL语句而已,并且已经优化好和编译好。

5. 关于使用建议:我们在学习阶段,必须会使用脚本写视图。如果是正式开发阶段,我们可以适当的使用可视化方式创建视图。

创建完毕后,把SQL语句优化好,再复制到你要创建的视图中。这个仅仅是为了省时间。必要的时候可以使用。

6. 视图还有一个非常重要的功能:比如我们在项目中会根据不同的角色,做不同的数据查询,这时候,我们在必要的时候完全可以

针对不同的用户角色,设计不同的视图,保证数据的安全。

二.存储过程

1. 概念:存储过程就是编写到数据库服务器端的SQL语句,存储过程的内容不仅仅是可以实现查询,也可以实现CRUD同时操作。

使用选择:如果仅仅是查询,建议你使用视图。尤其是针对不同的角色需要调用不同的视图。这时候视图是非常方便的。

2. 分类:系统存储过程(请大家自己学习一下,知道即可,可以随时查询)-->系统给我们提前定义好的,我们可以直接使用。

用户自定义存储过程(我们主要用的)

3. 好处:

【1】执行效率高。已经编译好,并保存到服务器端。只需要调用,必要的时候传递参数即可。

减轻客户端的压力。

【2】安全型好。客户端调用,只需要发送指令即可。数据安全有保障。

【3】维护方便。如果后续有改动,可以直接在服务器端修改即可,而客户端程序不用修改。

SQLSever存储过程

带输入参数的存储过程:

--存储过程编写
if exists(select * from sysobjects where name=Course__Procedure1)
drop procedure Course__Procedure1 
go
--创建存储过程
create procedure Course__Procedure1
--定义传入参数
--@CourseId int,
@CourseName nvarchar(50),
@CourseContent nvarchar(500),
@ClassHour int,
@Credit int,
@CategoryId int,
@TeacherId int
as
---在这里编写具体的存储过程内容
insert into Course(CourseName,CourseContent,ClassHour,Credit,CategoryId,TeacherId) 
values(@CourseName,@CourseContent,@ClassHour,@Credit,@CategoryId,@TeacherId);
go
--调用存储过程
exec Course__Procedure1 opencv从入门到放弃,opencv从入门到高级教程,20,3,10,10
--查询
select * from Course where CourseName=opencv从入门到放弃 ;

带参数默认值的存储过程

-编写带参数默认值的存储过程
if exists(select * from sysobjects where name=Course__Procedure2)
drop procedure Course__Procedure2
go
create procedure Course__Procedure2
---添加存储过程参数
@courseName varchar(50)=opencv高级教程,
@courseContent varchar(500)=opencv高级教程,包你学会不放弃,
@ClassHour int,
@Credit int,
@CategoryId int,
@TeacherId int
as 
---在这里添加具体的存储过程内容
insert into Course(CourseName,CourseContent,ClassHour,Credit,CategoryId,TeacherId)
values(@CourseName,@CourseContent,@ClassHour,@Credit,@CategoryId,@TeacherId);
go
--调用带默认参数值的存储过程,前两个参数使用默认值
exec Course__Procedure2 @ClassHour=10,@Credit=5,@CategoryId=12,@TeacherId=20
--调用带默认参数值的存储过程参数,第二个参数使用默认值
exec Course__Procedure2 @courseName=opencv图像处理教程,@ClassHour=10,@Credit=5,@CategoryId=12,@TeacherId=20
select * from Course where courseName=opencv图像处理教程

带输出参数的存储过程,使用output修饰

--输出参数的存储过程:使用output
if exists(select * from sysobjects where name=Course__Procedure3)
drop procedure Course__Procedure3
go
create procedure Course__Procedure3
---定义输出参数
@Count int output
as
--编写具体存储过程内容
select @Count= Count(*) from Course;
go
--调用存储过程,声明变量用declare
declare @Count int  --首先定义输出参数
exec Course__Procedure3 @Count output
--使用参数
select 商品总数=@Count
if exists(select * from sysobjects where name=select_usp_course1)
drop procedure select_usp_course1
go
create procedure select_usp_course1
--定义输入输出参数
@CountNum int output, ---定义输出参数
@CourseName nvarchar(50),
--@CourseContent nvarchar(500),
@CategoryId int
--@TeacherId int,
--@ClassHour int=1000,---带默认参数
--@Credit int=100---带默认值
as
select * from Course where Coursename=@CourseName;
select * from CourseCategory where CategoryId=@CategoryId;
select @CountNum=COUNT(*) from Course;
go
declare @CountNum int ;--声明输出变量
exec select_usp_course1 @CountNum output,C#入门,12

在C#中调用写好的存储过程

 

  #region 学员成绩管理

        /// <summary>
        /// 通过存储过程实现查询全校考试信息(通过存储过程)
        /// </summary>
        /// <returns>返回一个字典集合</returns>
        public Dictionary<string, string> QueryExamInfo()
        {
            string cmdText = "pro_QueryExamInfo";
            //定义输出参数,参数和数据库存储过程参数一致
            SqlParameter outparam1 = new SqlParameter("@stuCount", SqlDbType.Int);
            SqlParameter outparam2 = new SqlParameter("@agvCsharp", SqlDbType.Float);
            SqlParameter outparam3 = new SqlParameter("@agvServerDB", SqlDbType.Float);
            SqlParameter outparam4 = new SqlParameter("@absenceCount", SqlDbType.Int);
            outparam1.Direction = ParameterDirection.Output;
            outparam2.Direction = ParameterDirection.Output;
            outparam3.Direction = ParameterDirection.Output;
            outparam4.Direction = ParameterDirection.Output;
            SqlParameter[] outparam = new SqlParameter[] {
                outparam1,
                outparam2,
                outparam3,
                outparam4
            };
            SqlDataReader reader = SQLHelper.GetReader(cmdText, outparam, true);
            Dictionary<string, string> examInfoDic = null;
            //获取参考学生人数,平均成绩
            if (reader.Read())
            {
                examInfoDic = new Dictionary<string, string>()
                {
                    ["stuCount"] = reader["stuCount"].ToString(),
                    ["agvCsharp"] = reader["agvCsharp"].ToString(),
                    ["agvServerDB"] = reader["agvServerDB"].ToString(),
                    ["absenceCount"] = reader["absenceCount"].ToString()
                };
            }
            reader.Close();
            return examInfoDic;
        }

        public List<string> QueryAllAbsenceStudent()
        {
            string cmdText = "pro_QueryAllAbsenceStudent";
            List<string> stuNameList = new List<string>();
            SqlDataReader reader = SQLHelper.GetReader(cmdText);
            while (reader.Read())
            {
                stuNameList.Add(reader["StudentName"].ToString());
            }
            reader.Close();
            return stuNameList;
        }

        /// <summary>
        /// 按照班级查询考试信息
        /// </summary>
        /// <param name="ClassName"></param>
        /// <returns></returns>
        public Dictionary<string, string> QueryAbsenceInfoById(int ClassId)
        {
            string cmdText = "pro_QueryAbsenceInfoByClassId";
            //定义输入参数
            SqlParameter inputparam0 = new SqlParameter("@ClassId", ClassId);
            //定义输出参数
            SqlParameter outparam1 = new SqlParameter("@stuCount",SqlDbType.Int);
            SqlParameter outparam2 = new SqlParameter("@agvCsharp",SqlDbType.Float);
            SqlParameter outparam3 = new SqlParameter("@agvServerDB",SqlDbType.Float);
            SqlParameter outparam4 = new SqlParameter("@absenceCount",SqlDbType.Int);

            inputparam0.Direction = ParameterDirection.Input;
            outparam1.Direction = ParameterDirection.Output;
            outparam2.Direction = ParameterDirection.Output;
            outparam3.Direction = ParameterDirection.Output;
            outparam4.Direction = ParameterDirection.Output;
            SqlParameter[] param = new SqlParameter[] {
                inputparam0,
                outparam1,
                outparam2,
                outparam3,
                outparam4
            };
            SqlDataReader reader = SQLHelper.GetReader(cmdText, param, true);
            Dictionary<string, string> examInfoDic = null;
            //获取参考学生人数,平均成绩
            if (reader.Read())
            {
                examInfoDic = new Dictionary<string, string>()
                {
                    ["stuCount"] = reader["stuCount"].ToString(),
                    ["agvCsharp"] = reader["agvCsharp"].ToString(),
                    ["agvServerDB"] = reader["agvServerDB"].ToString(),
                    ["absenceCount"] = reader["absenceCount"].ToString()
                };
            }
            reader.Close();
            return examInfoDic;
        }

        /// <summary>
        /// 按照班级查询缺考人员
        /// </summary>
        /// <param name="ClassName"></param>
        /// <returns></returns>
        public List<String> QueryAbsenceStudents(int ClassId) 
        {
            string cmdText = "pro_QueryClassExamInfo";
            SqlParameter[] param = new SqlParameter[] { 
                new SqlParameter("@ClassId",ClassId)
            };
            SqlDataReader reader = SQLHelper.GetReader(cmdText,param,true);
            List<string> StuNamelist = new List<string>();
            while (reader.Read())
            {
                StuNamelist.Add(reader["StudentName"].ToString());
            }
            reader.Close();
            return StuNamelist;
        }
        #endregion

 

SQLSever视图和存储过程

上一篇:Access denied for user 'GC'@'localhost' (using password: YES)


下一篇:《人人都玩开心网:Ext JS+Android+SSH整合开发Web与移动SNS》销售排名第4,发篇ExtJS的文章(拖放树结点)庆祝下