面试准备(一)
谈谈你对ASP.NET底层原理的了解
谈到这个就不得不说说HTTP的请求处理流程了。作为一个程序员,你有没有思考过为什么在浏览器的地址栏中输入一个网址就能访问到相应的页面。类似于思考“为什么苹果往地上掉而不是往天上飘”,这种常识对于人们来说就好像是太阳天天东升西落一样被认为是理所当然的。但对于程序员来说,还是很有必要了解了解其底层原理的。事实上,当我们按下回车键的那短暂的一刻,IIS和.Net Framework已经做了大量的幕后工作了。
我们在开发过程中,常常会用到诸如HttpContext这样的类,但我们有没有想过这些类的构成和类的实体是如何创建的呢?回答类似这样的问题,首先需要了解IIS是如何处理页面请求的,这也是理解Form验证模式和Windows验证模式的基础。
当服务器接收到一个Http请求的时候,IIS首先根据文件的后缀名去处理这个请求(服务器处理一个.html页面和一个.aspx页面肯定是不一样的)。服务器获取所请求的页面(或文件)的后缀名以后,就会在服务器端寻找可以处理这这类后缀名的应用程序,之后IIS将直接把这个文件返还给客户端。能够处理各种后缀名的应用程序,通常被称为ISAPI应用程序(互联网服务器应用程序接口:实际上只是一个接口,起到一个代理作用,主要工作是映射所请求的页面或文件和与此后缀名相对应的实际的处理程序。)
从本质上讲,Asp.Net 主要是由一系列的类组成,这些类的主要目的就是将Http请求转变为对客户端的响应。HttpRuntime类是Asp.Net的一个主要入口,它有一个称作 ProcessRequest 的方法,这个方法以一个 HttpWorkerRequest 类作为参数。HttpRuntime 类几乎包含着关于单个 Http请求的所有信息:所请求的文件、服务器端变量、QueryString、Http 头信息 等等。Asp.Net 使用这些信息来加载、运行正确的文件,并且将这个请求转换到输出流中,一般来说,也就是HTML页面。(二般来说,也可以是图片)
谈谈你对.NET Core的了解
ASP.NET Core 是一个全新的开源、跨平台框架,可以用它来构建基于网络连接的现代云应用程序,比如:Web 应用,IoT(Internet Of Things,物联网)应用和移动后端等。ASP.NET Core可以运行在 .NET Core 或完整的 .NET Framework 之上,其架构为发布到云端或本地运行的应用提供了一个最佳的开发框架,由开销很小的模块化组件构成,这就保持了你构造解决方案的灵活性。你可以跨平台地在Windows、Mac和Linux等设备上开发和运行你的 ASP.NET Core 应用。ASP.NET Core 的源代码已经在 GitHub 上托管。
什么是存储过程
存储过程(Procedure)是一组为了完成特定功能的SQL语句集合,经编译后存储在数据库中,用户通过指定存储过程的名称并给出参数来执行。存储过程可以包含逻辑控制语句和数据操纵语句,可以接受输入参数、输出参数、返回单个或多个结果集以及返回值。
存储过程的优点?
- 减少网络通信量。调用一个行数不多的存储过程与直接调用SQL语句的网络通信量可能不会有很大的差别,可是如果存储过程包含上百行SQL语句,那么其性能绝对比一条一条的调用SQL语句要高得多。
- 执行速度更快。有两个原因:首先,在存储过程创建的时候,数据库已经对其进行了一次解析和优化。其次,存储过程一旦执行,在内存中就会保留一份这个存储过程,这样下次再执行同样的存储过程时,可以从内存中直接调用。
- 更强的适应性:由于存储过程对数据库的访问是通过存储过程来进行的,因此数据库开发人员可以在不改动存储过程接口的情况下对数据库进行任何改动,而这些改动不会对应用程序造成影响。
- 布式工作:应用程序和数据库的编码工作可以分别独立进行,而不会相互压制。
- 安全性高,可设定只有某此用户才具有对指定存储过程的使用权。
存储过程的缺点?
- 存储过程对应于专门的数据库,可移植性差;
- 存储过程需要专门的DBA编写;
- 存储过程容易混合业务逻辑,导致整个存储过程变得复杂和难以维护;
存储过程的分类
根据返回值类型的不同,我们可以将存储过程分为三类:
-
返回记录集的存储过程:返回记录集的存储过程的执行结果是一个记录集,典型的例子是从数据库中检索出符合某一个或几个条件的记录;
-
返回数值的存储过程(也可以称为标量存储过程):返回数值的存储过程执行完以后返回一个值,例如在数据库中执行一个有返回值的函数或命令;
-
以及行为存储过程:行为存储过程仅仅是用来实现数据库的某个功能,而没有返回值,例如在数据库中的更新和删除操作。
什么是系统存储过程?
系统存储过程是系统创建的存储过程,目的在于能够方便的从系统表中查询信息或完成与更新数据库表相关的管理任务或其他的系统管理任务。系统存储过程主要存储在master数据库中,以“sp”下划线开头的存储过程。尽管这些系统存储过程在master数据库中,但我们在其他数据库还是可以调用系统存储过程。有一些系统存储过程会在创建新的数据库的时候被自动创建在当前数据库中。

常见的系统存储过程有哪些?
exec sp_databases; --查看数据库 exec sp_tables; --查看表 exec sp_columns student;--查看列 exec sp_helpIndex student;--查看索引 exec sp_helpConstraint student;--约束 exec sp_stored_procedures; exec sp_helptext 'sp_stored_procedures';--查看存储过程创建、定义语句 exec sp_rename student, stuInfo;--修改表、索引、列的名称 exec sp_renamedb myTempDB, myDB;--更改数据库名称 exec sp_defaultdb 'master', 'myDB';--更改登录名的默认数据库 exec sp_helpdb;--数据库帮助,查询数据库信息 exec sp_helpdb master;
系统存储过程示例
--表重命名 exec sp_rename 'stu', 'stud'; select * from stud; --列重命名 exec sp_rename 'stud.name', 'sName', 'column'; exec sp_help 'stud'; --重命名索引 exec sp_rename N'student.idx_cid', N'idx_cidd', N'index'; exec sp_help 'student'; --查询所有存储过程 select * from sys.objects where type = 'P'; select * from sys.objects where type_desc like '%pro%' and name like 'sp%';
用户自定义存储过程
1、创建语法
create proc | procedure pro_name [{@参数数据类型} [=默认值] [output], {@参数数据类型} [=默认值] [output], .... ] as SQL_statements
2、执行存储过程与删除存储过程
在未进入如何写存储过程的主体前,先介绍一下执行存储过程和删除存储过程,这两个操作应该是比较简单的。
- 执行存储过程
{ EXECUTE | EXEC} proc_name [@pram=value [OUTPUT]]
在带参数的情况下,优先使用@parameter=value的形式。如果参数有默认值,并且传入的也是默认值,则可以省略参数;如果参数是一个输出参数,则需要携带OUTPUT关键字。
- 删除存储过程
DROP PROCEDURE proc_name
3、创建不带参数的存储过程
--创建存储过程 if (exists (select * from sys.objects where name = 'proc_get_student')) drop proc proc_get_student go create proc proc_get_student as select * from student; --调用、执行存储过程 exec proc_get_student;
4、分支语句
与其他开发语言类似,IF后面可以跟ELSE也可以不跟,可以有ELSE IF也可以没有。同时需要注意一点的是,IF后只执行一块代码,如果要执行多条语句,必须用BEGIN-END包裹起来。
IF @bookAble=1
SET @bookName='SQL YES'
ELSE
BEGIN
SET @bookName='SQL NO'
END
5、循环语句
WHILE bool_expression
{ sql_statement | statement_block }
[ BREAK | CONTINUE ]
--循环实例
DECLARE @count INT;
SET @count = 1;
WHILE @count<10
BEGIN
SET @count += 1
PRINT @count
END
6、使用RETURN
RETURN语句可以立刻停止存储过程的执行,任何位于RETURN语句之外的语句都不会被执行。在存储过程结束的地方,实际上也是在逻辑上执行了一个RETURN,其返回的值为0,表示成功执行。与输出参数的对比:输出参数用于将信息返回到调用存储过程的代码中,并且它可以是任何数据类型。而RETURN只能返回整数值,通常用于表示成功或失败。
7、修改存储过程
--修改存储过程 alter proc proc_get_student as select * from student;
8、创建带参数的存储过程
--带参存储过程 if (object_id('proc_find_stu', 'P') is not null) drop proc proc_find_stu go create proc proc_find_stu(@startId int, @endId int) as select * from student where id between @startId and @endId go exec proc_find_stu 2, 4;
9、创建带通配符参数的存储过程
--带通配符参数存储过程 if (object_id('proc_findStudentByName', 'P') is not null) drop proc proc_findStudentByName go create proc proc_findStudentByName(@name varchar(20) = '%j%', @nextName varchar(20) = '%') as select * from student where name like @name and name like @nextName; go exec proc_findStudentByName; exec proc_findStudentByName '%o%', 't%';
10、创建带输出参数的存储过程
if (object_id('proc_getStudentRecord', 'P') is not null) drop proc proc_getStudentRecord go create proc proc_getStudentRecord( @id int, --默认输入参数 @name varchar(20) out, --输出参数 @age varchar(20) output--输入输出参数 ) as select @name = name, @age = age from student where id = @id and sex = @age; go -- declare @id int, @name varchar(20), @temp varchar(20); set @id = 7; set @temp = 1; exec proc_getStudentRecord @id, @name out, @temp output; select @name, @temp; print @name + '#' + @temp;
11、不缓存存储过程
--WITH RECOMPILE 不缓存 if (object_id('proc_temp', 'P') is not null) drop proc proc_temp go create proc proc_temp with recompile as select * from student; go exec proc_temp;
12、加密存储过程
--加密WITH ENCRYPTION if (object_id('proc_temp_encryption', 'P') is not null) drop proc proc_temp_encryption go create proc proc_temp_encryption with encryption as select * from student; go exec proc_temp_encryption; exec sp_helptext 'proc_temp'; exec sp_helptext 'proc_temp_encryption';
13、带游标参数的存储过程
if (object_id('proc_cursor', 'P') is not null) drop proc proc_cursor go create proc proc_cursor @cur cursor varying output as set @cur = cursor forward_only static for select id, name, age from student; open @cur; go --调用 declare @exec_cur cursor; declare @id int, @name varchar(20), @age int; exec proc_cursor @cur = @exec_cur output;--调用存储过程 fetch next from @exec_cur into @id, @name, @age; while (@@fetch_status = 0) begin fetch next from @exec_cur into @id, @name, @age; print 'id: ' + convert(varchar, @id) + ', name: ' + @name + ', age: ' + convert(char, @age); end close @exec_cur; deallocate @exec_cur;--删除游标
14、分页存储过程
---存储过程、row_number完成分页 if (object_id('pro_page', 'P') is not null) drop proc proc_cursor go create proc pro_page @startIndex int, @endIndex int as select count(*) from product ; select * from ( select row_number() over(order by pid) as rowId, * from product ) temp where temp.rowId between @startIndex and @endIndex go --drop proc pro_page exec pro_page 1, 4 -- --分页存储过程 if (object_id('pro_page', 'P') is not null) drop proc pro_stu go create procedure pro_stu( @pageIndex int, @pageSize int ) as declare @startRow int, @endRow int set @startRow = (@pageIndex - 1) * @pageSize +1 set @endRow = @startRow + @pageSize -1 select * from ( select *, row_number() over (order by id asc) as number from student ) t where t.number between @startRow and @endRow; exec pro_stu 2, 2;
Raiserror
Raiserror返回用户定义的错误信息,可以指定严重级别,设置系统变量记录所发生的错误。
语法如下:
Raiserror({msg_id | msg_str | @local_variable}
{
, severity, state}
[,argument[,…n]]
[with option[,…n]]
)
-
# msg_id:在sysmessages系统表中指定的用户定义错误信息
-
# msg_str:用户定义的信息,信息最大长度在2047个字符。
-
# severity:用户定义与该消息关联的严重级别。当使用msg_id引发使用sp_addmessage创建的用户定义消息时,raiserror上指定严重性将覆盖sp_addmessage中定义的严重性。
-
任何用户可以指定0-18直接的严重级别。只有sysadmin固定服务器角色常用或具有alter trace权限的用户才能指定19-25直接的严重级别。19-25之间的安全级别需要使用with log选项。
-
# state:介于1至127直接的任何整数。State默认值是1。
raiserror('is error', 16, 1);
select * from sys.messages;
--使用sysmessages中定义的消息
raiserror(33003, 16, 1);
raiserror(33006, 16, 1);
简单图书管理系统存储过程实例
简单图书馆管理系统示例
--简单图书馆管理系统
--创建reader表
CREATE TABLE reader
(
reader_id INT IDENTITY(1,1) NOT NULL,
reader_email VARCHAR(120) NOT NULL,
reader_name NVARCHAR(16) NULL,
reader_password VARCHAR(16) NOT NULL,
reader_enable BIT DEFAULT(1) NOT NULL,
PRIMARY KEY(reader_id)
)
--创建book表
CREATE TABLE book
(
book_id INT IDENTITY(1,1) NOT NULL,
book_name NVARCHAR(50) NOT NULL,
book_stock INT NOT NULL, --书的库存
book_borrowed INT DEFAULT(0) NOT NULL, --书的已借出数量
book_enable BIT DEFAULT(1) NOT NULL,
CHECK (book_stock>=0),
CHECK (book_borrowed>=0),
CHECK (book_borrowed <= book_stock),
PRIMARY KEY(book_id)
)
--创建borrow表
CREATE TABLE borrow
(
borrow_id INT IDENTITY(1,1) NOT NULL,
book_id INT NOT NULL,
reader_id INT NOT NULL,
borrow_start_date SMALLDATETIME NOT NULL, --借阅开始日期
borrow_end_date SMALLDATETIME NOT NULL, --借阅归还日期
borrow_is_returned BIT DEFAULT(0) NOT NULL, --归还标记
CHECK(borrow_start_date <=borrow_end_date),
PRIMARY KEY(borrow_id),
FOREIGN KEY(book_id) REFERENCES book(book_id),
FOREIGN KEY(reader_id) REFERENCES reader(reader_id)
)
--增加书籍存储过程
CREATE PROC proc_book_add
(
@book_id INT OUTPUT,
@book_name NVARCHAR(50),
@book_stock INT
)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO book (book_name,book_stock) VALUES (@book_name,@book_stock)
--返回生成的唯一ID号
SET @book_id=SCOPE_IDENTITY();
END
--检查某本书是否有库存
CREATE PROC proc_book_has_stock
(
@book_id INT,
@has_stock BIT OUTPUT
)
AS
BEGIN
DECLARE @stockNum INT;
DECLARE @borrowNum INT;
SET NOCOUNT ON;
SELECT @borrowNum=book_borrowed,@stockNum=book_stock FROM book WHERE book_id=@book_id;
--比较是否有库存
IF (@stockNum > @borrowNum)
SET @has_stock = 1
ELSE
SET @has_stock = 0
END
--借阅图书
CREATE PROC proc_borrow_add
(
@book_id INT,
@reader_id INT,
@borrow_start_date SMALLDATETIME,
@borrow_end_date SMALLDATETIME
)
AS
BEGIN
SET NOCOUNT ON;
--设置事务处理
BEGIN TRAN
--更新图书的借阅量+1
UPDATE book SET book_borrowed=book_borrowed+1
--插入一条图书借阅信息
INSERT INTO borrow (book_id,reader_id,borrow_start_date,borrow_end_date) VALUES (@book_id,@reader_id,@borrow_start_date,@borrow_end_date)
COMMIT
END
--归还图书
CREATE PROC proc_borrow_return
(
@borrow_id INT
)
AS
BEGIN
DECLARE @bookId INT;
SET NOCOUNT ON;
--设置事务处理
BEGIN TRAN
--获取book的唯一编号
SELECT @bookId=book_id FROM borrow WHERE borrow_id=@borrow_id
--更新borrow的归还标记为1
UPDATE borrow SET borrow_is_returned=1 WHERE borrow_id=@borrow_id
--更新书的已借阅量-1
UPDATE book SET book_borrowed=book_borrowed-1 WHERE book_id=@bookId
COMMIT
END
关于存储过程使用的争论,我不倾向于尽可能使用存储过程,个人认为:
-
运行速度: 大多数高级的数据库系统都有statement cache的,所以编译sql的花费没什么影响。但是执行存储过程要比直接执行sql花费更多(检查权限等),所以对于很简单的sql,存储过程没有什么优势。
-
网络负荷:如果在存储过程中没有多次数据交互,那么实际上网络传输量和直接sql是一样的。
-
团队开发:很遗憾,比起成熟的IDE,没有什么很好存储过程的IDE工具来支持,也就是说,这些必须手工完成。
-
安全机制:对于传统的C/S结构,连接数据库的用户可以不同,所以安全机制有用;但是在web的三层架构中,数据库用户不是给用户用的,所以基本上,只有一个用户,拥有所有权限(最多还有一个开发用户)。这个时候,安全机制有点多余。
-
用户满意:实际上这个只是要将访问数据库的接口统一,是用存储过程,还是EJB,没太大关系,也就是说,在三层结构中,单独设计出一个数据访问层,同样能实现这个目标。
-
开发调试:一样由于IDE的问题,存储过程的开发调试要比一般程序困难(老版本DB2还只能用C写存储过程,更是一个灾难)。
-
移植性:算了,这个不用提,反正一般的应用总是绑定某个数据库的,不然就无法靠优化数据库访问来提高性能了。
-
维护性:的确,存储过程有些时候比程序容易维护,这是因为可以实时更新DB端的存储过程,但是在3层结构下,更新server端的数据访问层一样能实现这个目标,可惜现在很多平台不支持实时更新而已。
现在,我认为的原则是:所有数据访问在应用层封装为数据访问层,在那里,如果SQL简单的话,直接用SQL;如果SQL复杂,或者数据交互多且中间数据最后不会用到,使用存储过程。其他凭经验吧。
事务处理
什么是事务?
事务是指做为单个逻辑工作单元的一系列操作,它保证成批的T-SQL操作要么全部执行,要么全部不执行。
事务的创建、提交、回滚、保留点
-
BEGIN TRAN[SACTION] [ tran_name ]
-
COMMIT [ TRAN[SACTION] tran_name ]
-
ROLLBACK [ TRAN[SACTION] tran_name ]
-
SAVE TRAN[SACTION] tran_name]
如何优化sql
-
少用子查询:尽量少用子查询,因为子查询会产生临时表;除非像count(*)临时表很小的。
-
少用SELECT *:每次看到SELECT *都需要用怀疑的眼光审视,是否真的需要返回全部的列?取出全部的列,会让优化器无法完成索引覆盖扫描这类优化,还会为服务器带来额外的I/O、内存和CPU的消耗。
-
查询必要的记录:一个常见的错误是常常会误以为SQL Server只会返回需要的数据,实际上SQL Server却是先返回全部结果集再进行计算,建议在查询后面加上LIMIT。
-
不要重复查询相同的数据:不断执行相同的查询,然后每次都会返回完全相同的数据。可以采用的方案是初次查询的时候将这个数据缓存起来,需要的时候从缓存中取出,这样性能显然会更好。
-
COUNT查询优化:COUNT()聚合函数的作用: 统计某一个列值的数量,也可以统计行数。需要注意的是统计列值时要求列值是非空的(不统计NULL),COUNT()查询尽可能少的行。
举个例子:如果我们直接查 id>100 的记录,涉及到的有两千多万行记录扫描。但是由于COUNT()特性,我们可以用 count() - (id<100)的做法,这样扫描的行就只有100行了。
-
Where子句中,where表之间的连接必须写在其他Where条件之前,那些可以过滤掉最大数量记录的条件必须写在Where子句的末尾.HAVING最后。
-
用EXISTS替代IN、用NOT EXISTS替代NOT IN。
-
避免在索引列上使用计算。
-
避免在索引列上使用IS NULL和IS NOT NULL。
-
对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
-
应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描。
-
应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。
SQL Server索引
什么是索引
索引就是数据表中数据和相应的存储位置的列表,利用索引可以提高在表或视图中的查找数据的速度。
索引分类
数据库中索引主要分为两类:聚集索引和非聚集索引。SQL Server 2005还提供了唯一索引、索引视图、全文索引、xml索引等等。聚集索引和非聚集索引是数据库引擎中索引的基本类型,是理解其他类型索引的基础。
- 聚集索引是指表中数据行的物理存储顺序和索引的存储顺序完全相同。聚集索引根据索引顺序物理地重新排列了用户插入到表中的数据,因此,每个表只能创建一个聚集索引。聚集索引经常创建在表中经常被搜索到的列或按顺序访问的列上。在默认情况下,主键约束自动创建聚集索引。
- 非聚集索引不改变表中数据列的物理存储位置,数据与索引分开存储,通过索引指向的地址与表中的数据发生关系。非聚集索引没有改变表中物理行的位置,索引可以在以下情况下使用非聚集索引:
- 如果某个字段的数据唯一性比较高
- 如果查询所得到的数据量比较少
聚集索引与非聚集索引的区别
聚集索引 | 非聚集索引 |
---|---|
每个表只允许创建一个聚集索引 | 最多可以有249个非聚集索引 |
物理的重排表中的数据以符合索引约束 | 创建一个键值列表,键值指向数据在数据页中的位置 |
用于经常查找数据的列 | 用于从表中查找单个值的列 |
其它类型索引
- 唯一索引:如果希望索引键都不同,可以创建唯一索引。聚集索引和非聚集索引都可以是唯一索引。
- 包含新列索引:索引列的最大数量是16个,索引列的字节总数的最高值是900。如果当多个列的字节总数大于900,切又想在这些劣种都包含索引是,可以使用包含性列索引
- 视图索引:提供视图查询效率,可以视图的索引物理化,也就是说将结果集永久存储在索引中,可以创建视图索引。
- XML索引:是与xml数据关联的索引形式,是XML二进制blob的已拆分持久表示形式
- 全文索引:一种特殊类型的基于标记的功能性功能,用于帮助在字符串中搜索赋值的词
创建索引
create [unique] [clustered | noclustered]
index index_name
on table_name (column_name ...)
[with fillfactor=x]
unique唯一索引、clustered聚集索引noclustered非聚集索引、fillfactor填充因子大小,范围在0-100直接,表示索引页填满的空间所占的百分比。
if (exists (select * from sys.indexes where name = 'idx_stu_name'))
drop index student.idx_stu_name
go
create index idx_stu_name
on
student(name);
--联合索引
if (exists (select * from sys.indexes where name = 'idx_uqe_clu_stu_name_age'))
drop index student.idx_uqe_clu_stu_name_age
go
create unique clustered index idx_uqe_clu_stu_name_age
on student(name, age);
if (exists (select * from sys.indexes where name = 'idx_cid'))
drop index student.idx_cid
go
if (exists (select * from sys.indexes where name = 'idx_cid'))
drop index student.idx_cid
go
--非聚集索引
create nonclustered index idx_cid
on
student (cid)
with fillFactor = 30; --填充因子
--聚集索引
if (exists (select * from sys.indexes where name = 'idx_sex'))
drop index student.idx_sex
go
create clustered index idx_sex
on
student(sex);
--聚集索引
if (exists (select * from sys.indexes where name = 'idx_name'))
drop index student.idx_name
go
create unique index idx_name
on
student(name);
-
适合的创建索引的列:当数据库的某一列被频繁的用于数据库查询时,或者该列用于数据库进行排序时可以创建成索引
-
不适合创建索引的列:如果列中有几个不同的值,或者表中仅包含几行值,则不推荐为其创建索引。因为索引在搜索数据所花的时间比在表中逐行搜索的时间更长
SQL Server视图
视图就是一个虚拟的数据表,该数据表中的数据记录是有一条查询语句的查询结果得到的
创建视图准则
-
视图名称必须遵循标识符的规则,该名称不得与该架构的如何表的名称相同
-
你可以对其他视图创建视图。允许嵌套视图,但嵌套不得超过32层。视图最多可以有1024个字段
-
不能将规则和default定义于视图相关联
-
视图的查询不能包含compute子句、compute by子句或into关键字
-
定义视图的查询不能包含order by子句,除非在select 语句的选择列表中还有top子句
下列情况必须指定视图中每列的名称:
-
视图中的如何列都是从算术表达式、内置函数或常量派生而来
-
视图中有两列或多列具有相同名称(通常由于视图定义包含联接,因此来自两个或多个不同的列具有相同的名称)
-
希望视图中的列指定一个与其原列不同的名称(也可以在视图中重命名列)。无论是否重命名,视图列都会继承原列的数据类型
创建视图
if (exists (select * from sys.objects where name = 'v_stu'))
drop view v_stu
go
create view v_stu
as
select id, name, age, sex from student;
修改视图
alter view v_stu
as
select id, name, sex from student;
alter view v_stu(编号, 名称, 性别)
as
select id, name, sex from student
go
select * from v_stu;
select * from information_schema.views;
加密视图
if (exists (select * from sys.objects where name = 'v_student_info'))
drop view v_student_info
go
create view v_student_info
with encryption --加密
as
select id, name, age from student
go
--view_definition is null
select * from information_schema.views
where table_name like 'v_stu';
说一下你选择这个行业的理由(行业前景)
我觉得.NET大有前景,.NET凭借其自身完整的框架结构以及微软现在的各种开源,将在客户端与Web服务以及大型企业级应用中能够有更好的发展前景。随着.NET5的诞生,今后就可能Web开发、桌面开发、移动开发、游戏开发、物联网开发、人工智能、云开发这几大方向都能用.NET实现。
你个人的职业目标是什么
目前的话只能算是个初级开发工程师,所以先努力学习技术,努力工作,争取一到两年成长为中级开发工程师,努力工作几年后往产品经理这个方向发展,因为感觉自己对产品的策划会比较感兴趣,也喜欢琢磨用户体验。之所以这样选择是因为对技术有了一定的了解后,当走向产品策划的时候,对于产品的需求可能会更加贴切实际。
谈谈你对产品经理这个岗位的了解
首先,产品经理并不意味着你不会再触碰代码了。我喜欢与人探讨分析、交流,在这一点上我觉得适合产品经理这个岗位。产品经理应该具备以下几点能力:
- 产品战略和发展规划的能力:比如说老板要求公司在3年内要上市,那么这个时候你就要围绕如何推动公司上市来开发产品,这个产品的目标市场是什么、目标用户是什么、盈利模式是什么、你这个产品的独有的特点和风格是什么…。
- 挖掘和分析需求的能力。
- 推动产品目标实现的能力。
- 较强的团队合作和管理能力。
面试最后问的问题
-
你在公司的一天一般是如何度过的?
-
能否简单介绍下贵公司的业务与未来的发展战略
-
贵公司最让你自豪的企业文化是什么?
-
团队、公司现在面临的最大挑战是什么?
-
对于未来加入这个团队,你对我的期望是什么?
-
很好奇,你最不喜欢公司的哪一点?
-
公司的组织架构是怎样的?
-
公司的发展控件及发展渠道