您的位置:首页 > 职场人生

面试中的SQL分析一

2014-08-05 14:19 204 查看

1.关于分组函数

一.分组查询

1.使用group by进行分组查询

在使用group by关键字时,在select列表中可以指定的项目是有限制的,select语句中仅许以下几项:

〉被分组的列

〉为每个分组返回一个值得表达式,例如用一个列名作为参数的聚合函数

group by的使用在这只写几个例子吧:

例:

select courseID,avg(score) as 课程平均成绩

from score

group by courseID

例:

select studentID as 学员编号,courseID as 内部测试,avg(score) as 内部测试平均成绩

from score

group by studentID,courseID

2.使用having子句进行分组筛选

where子句只能对没有分组统计前的数据行进行筛选,对分组后的条件的筛选必须使用having子句

例:

select studentID as 学员编号,courseID as 内部测试,avg(score) as 内部测试平均成绩

from score

group by studentID,courseID

having avg(score)>60

在select语句中,where、group by、having子句和统计函数的执行次序如下:

where子句从数据源中去掉不符合去搜索条件的数据;group by子句搜集数据行到各个组中,统计函数为各个组计算统计值;having子句去掉不符合其组搜索条件的各组数据行 。

今天要做一个查询统计功能,一开始有点犯难,上午尝试大半天才写出统计sql语句,才发现自己sql分组查询及聚集函数没学好;其实就是group by子句和几个聚集函数,熟练使用统计功能很简单。在此总结下今天查询统计是用到的几个sql函数。

SQL聚集函数

sum函数 sum函数用于计算查询表中指定字段中所有 记录值的总和。 语法:sum(exp) 说明:该函数不计算包含Null 值的字段。

例:SELECT SUM(population) FROM bbc 这里的SUM作用在所有返回记录的 population字段上,结果就是该查询只返回 一个结果,即所有国家的总人口数。

avg函数 Avg函数是用来计算特定查询字段中的一组数值的 算术平均值(将全部值的总和除以值的数目)。 语法:avg(exp) 说明:该函数只能对数值类型的字段进行计算。 例:求所有雇员薪水的平均值。 SELECT AVG(emp_salary) FROM employee;

count函数 count函数是用来计算查询表中的记录数。 语法:count(exp) 说明:count函数不计算具有Null字段的记录,但如 果将exp设置为星号(*),则count函数将计算所有记 录的总量,包括有Null的字段的记录。Distinct短句可以取消指定列中的重复值 sql除了不允许对count(*)使用distinct,对其 余情况都能用distinct,但一般情况下是没有 必要用的,除非你觉得的确是需要用distinct。

min函数 min函数是用来从查询表中返回指定字段中 的最小值。 语法:min(exp)

max函数 max函数是用来从查询表中返回指定字段中 的最大值。 语法:max(exp)

GROUP BY子句

对记录的分组是通过关键字 GROUP BY 实现的, GROUP BY 后面跟着一个定义组的构成的属性列 表。 如果我们使用语句 GROUP BY A1,……, Ak 我们就把关系分成了组,这样当且仅当两条记录 在所有属性 A1,……, Ak 上的值达成一致,它们才 是同一组的。 SQL 允许我们把一个表里面的记录用GROUP BY 分成组。 然后上面描述的聚集操作符可以应用于 这些组上 (也就是说,聚集操作符的值不再是对 所有声明的列的值进行操作,
而是对一个组的所 有值进行操作。这样聚集函数是为每个组独立地 进行计算的
。)

当在查询中没有使用GROUP BY子句时,数据库就把数据表 中的所有行为作为一个组来处理。通常情况下,我们并不希 望是这样的。多数用户都能理解组的概念,但在使用的时候 却很快就陷入 麻烦中。有一个技巧是:如果有一列在 GROUP BY子句中没有提到,就必须对它进行累计。换句话 说,就是必须对select中那些不包括在GROUP BY子句中的所有列使 用上面提到过的一个函数。

请注意如果要让一个使用 GROUP BY 和聚集操 作符的查询的结果有意义, 那么用于分组的属性 也必须出现在目标列表中。 所有没有在 GROUP BY 子句里面出现的属性都只能通过使用聚集函数 来选择。 否则就不会有唯一的数值与其它字段关 联. 还要注意的是在聚集上聚集是没有意义的,比如, AVG(MAX(sno)), 因为 SELECT 只做一个回合 的分组和聚集.你可以获得这样的结果, 方法是 使用临时表或者在 FROM 子句中使用一个子 SELECT 做第一个层次的聚集。

总结:

在带有group by 子句的查询语句中,在select 列表中指定的列要么是group by 子句中指定的列,要么包含聚组函数

查询语句的select 和group by ,having 子句是聚组函数唯一出现的地方,在where 子句中不能使用聚组函数。

当在gropu by 子句中使用having 子句时,查询结果中只返回满足having条件的组。在一个sql语句中可以有where子句和having子句。having 与where 子句类似,均用于设置限定条件。where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行。having 子句的作用是筛选满足条件的组,即在分组之后过滤数据,条件中经常包含聚组函数,使用having 条件显示特定的组,也可以使用多个分组标准进行分组。

SQL分组查询实例分析

下面的查询从说法上可以算得上是分组查询了,但是分组查询是不是就是指用group by来操作呢,我想在看了下面的例子后你会有清楚的答案。

create table testTable([id] int,[name] varchar(10),[dept] varchar(10),[salary] int)
insert testTable select 1,'tom','财务',4900
union all select 2,'tim','工程',7890
union all select 3,'kitty','财务',8930
union all select 4,'luck','工程',890
union all select 5,'kiidg','管理',850
union all select 6,'lily','财务',8300
union all select 7,'tki','工程',2900

select * from testTable order by dept,salary desc

--在所有部门中工资最高的2名员工
select top 2 * from testTable order by salary Desc

--各部门中工资最高的2名员工
--方法一:
select * from testTable as t
where id  in
(select top 2 id from testTable  where t.dept=dept order by salary Desc )
order by dept,salary desc

--方法二:
select id,[name],dept,salary
from
(
select *,row_number() over (partition by dept order by salary desc) rank from testTable
) T
where T.rank<=2


再看一个例子:

数据表:

姓名 科目 分数

张三 语文 80

张三 数学 98

张三 英语 65

李四 语文 70

李四 数学 80

李四 英语 90

期望查询结果:

姓名 语文 数学 英语

张三 80 98 65

李四 70 80 90

create table testScore
(
tid int primary key identity(1,1),
tname varchar(30) null,
ttype varchar(10) null,
tscor int null
)
go
---插入数据
insert into testScore values ('张三','语文',80)
insert into testScore values ('张三','数学',98)
insert into testScore values ('张三','英语',65)
insert into testScore values ('李四','语文',70)
insert into testScore values ('李四','数学',80)
insert into testScore values ('李四','英语',90)

select tname as '姓名' ,
max(case ttype when '语文' then tscor else 0 end) '语文',
max(case ttype when '数学' then tscor else 0 end) '数学',
max(case ttype when '英语' then tscor else 0 end) '英语'
from testScore
group by tname


再看看下面的例子(该例子摘自网络):

有如下数据:(为了看得更清楚,我并没有使用国家代码,而是直接用国家名作为Primary Key)

国家(country)人口(population)
中国600
美国100
加拿大100
英国200
法国300
日本250
德国200
墨西哥50
印度250
根据这个国家人口数据,统计亚洲和北美洲的人口数量。应该得到下面这个结果。

人口
亚洲1100
北美洲250
其他700
想要解决这个问题,你会怎么做?生成一个带有洲Code的View,是一个解决方法,但是这样很难动态的改变统计的方式。

如果使用Case函数,SQL代码如下:

SELECT  SUM(population),
CASE country
WHEN '中国'     THEN '亚洲'
WHEN '印度'     THEN '亚洲'
WHEN '日本'     THEN '亚洲'
WHEN '美国'     THEN '北美洲'
WHEN '加拿大'  THEN '北美洲'
WHEN '墨西哥'  THEN '北美洲'
ELSE '其他' END
FROM    Table_A
GROUP BY CASE country
WHEN '中国'     THEN '亚洲'
WHEN '印度'     THEN '亚洲'
WHEN '日本'     THEN '亚洲'
WHEN '美国'     THEN '北美洲'
WHEN '加拿大'  THEN '北美洲'
WHEN '墨西哥'  THEN '北美洲'
ELSE '其他' END;


同样的,我们也可以用这个方法来判断工资的等级,并统计每一等级的人数。SQL代码如下;
SELECT
CASE WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600  THEN '2'
WHEN salary > 600 AND salary <= 800  THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL END salary_class,
COUNT(*)
FROM    Table_A
GROUP BY
CASE WHEN salary <= 500 THEN '1'
WHEN salary > 500 AND salary <= 600  THEN '2'
WHEN salary > 600 AND salary <= 800  THEN '3'
WHEN salary > 800 AND salary <= 1000 THEN '4'
ELSE NULL END;


对于groupby后面一般都是跟一个列名,但在该例子中通过case语句使分组变得跟强大了。

二,用一个SQL语句完成不同条件的分组。

有如下数据

国家(country)性别(sex)人口(population)
中国1340
中国2260
美国145
美国255
加拿大151
加拿大249
英国140
英国260
按照国家和性别进行分组,得出结果如下

国家
中国340260
美国4555
加拿大5149
英国4060
普通情况下,用UNION也可以实现用一条语句进行查询。但是那样增加消耗(两个Select部分),而且SQL语句会比较长。

下面是一个是用Case函数来完成这个功能的例子

SELECT country,
SUM( CASE WHEN sex = '1' THEN
population ELSE 0 END),  --男性人口
SUM( CASE WHEN sex = '2' THEN
population ELSE 0 END)   --女性人口
FROM  Table_A
GROUP BY country;


三,在Check中使用Case函数。

在Check中使用Case函数在很多情况下都是非常不错的解决方法。可能有很多人根本就不用Check,那么我建议你在看过下面的例子之后也尝试一下在SQL中使用Check。

下面我们来举个例子

公司A,这个公司有个规定,女职员的工资必须高于1000块。如果用Check和Case来表现的话,如下所示
CONSTRAINT check_salary CHECK
( CASE WHEN sex = '2'
THEN CASE WHEN salary > 1000
THEN 1 ELSE 0 END
ELSE 1 END = 1 )


如果单纯使用Check,如下所示
CONSTRAINT check_salary CHECK
( sex = '2' AND salary > 1000 )


女职员的条件倒是符合了,男职员就无法输入了。

四,根据条件有选择的UPDATE。

例,有如下更新条件

工资5000以上的职员,工资减少10%
工资在2000到4600之间的职员,工资增加15%

很容易考虑的是选择执行两次UPDATE语句,如下所示

--条件1
UPDATE Personnel
SET salary = salary * 0.9
WHERE salary >= 5000;
--条件2
UPDATE Personnel
SET salary = salary * 1.15
WHERE salary >= 2000 AND salary < 4600;


但是事情没有想象得那么简单,假设有个人工资5000块。首先,按照条件1,工资减少10%,变成工资4500。接下来运行第二个SQL时候,因为这个人的工资是4500在2000到4600的范围之内, 需增加15%,最后这个人的工资结果是5175,不但没有减少,反而增加了。如果要是反过来执行,那么工资4600的人相反会变成减少工资。暂且不管这个规章是多么荒诞,如果想要一个SQL 语句实现这个功能的话,我们需要用到Case函数。代码如下:

UPDATE Personnel
SET salary = CASE WHEN salary >= 5000
             THEN salary * 0.9
WHEN salary >= 2000 AND salary < 4600
THEN salary * 1.15
ELSE salary END;


这里要注意一点,最后一行的ELSE salary是必需的,要是没有这行,不符合这两个条件的人的工资将会被写成NUll,那可就大事不妙了。在Case函数中Else部分的默认值是NULL,这点是需要注意的地方。

这种方法还可以在很多地方使用,比如说变更主键这种累活。

一般情况下,要想把两条数据的Primary key,a和b交换,需要经过临时存储,拷贝,读回数据的三个过程,要是使用Case函数的话,一切都变得简单多了。

p_keycol_1col_2
a1张三
b2李四
c3王五
假设有如上数据,需要把主键
a
b
相互交换。用Case函数来实现的话,代码如下

UPDATE SomeTable
SET p_key = CASE WHEN p_key = 'a'
THEN 'b'
WHEN p_key = 'b'
THEN 'a'
ELSE p_key END
WHERE p_key IN ('a', 'b');


同样的也可以交换两个Unique key。需要注意的是,如果有需要交换主键的情况发生,多半是当初对这个表的设计进行得不够到位,建议检查表的设计是否妥当。

五,两个表数据是否一致的检查。

Case函数不同于DECODE函数。在Case函数中,可以使用BETWEEN,LIKE,IS NULL,IN,EXISTS等等。比如说使用IN,EXISTS,可以进行子查询,从而 实现更多的功能。

下面具个例子来说明,有两个表,tbl_A,tbl_B,两个表中都有keyCol列。现在我们对两个表进行比较,tbl_A中的keyCol列的数据如果在tbl_B的keyCol列的数据中可以找到, 返回结果'Matched',如果没有找到,返回结果'Unmatched'。

要实现下面这个功能,可以使用下面两条语句

--使用IN的时候
SELECT keyCol,
CASE WHEN keyCol IN ( SELECT keyCol FROM tbl_B )
THEN 'Matched'
ELSE 'Unmatched' END Label
FROM tbl_A;
--使用EXISTS的时候
SELECT keyCol,
CASE WHEN EXISTS ( SELECT * FROM tbl_B
WHERE tbl_A.keyCol = tbl_B.keyCol )
THEN 'Matched'
ELSE 'Unmatched' END Label
FROM tbl_A;


使用IN和EXISTS的结果是相同的。也可以使用NOT IN和NOT EXISTS,但是这个时候要注意NULL的情况。

六,在Case函数中使用合计函数

假设有下面一个表

学号(std_id)课程ID(class_id)课程名(class_name)主修flag(main_class_flg)
1001经济学Y
1002历史学N
2002历史学N
2003考古学Y
2004计算机N
3004计算机N
4005化学N
5006数学N
有的学生选择了同时修几门课程(100,200)也有的学生只选择了一门课程(300,400,500)。选修多门课程的学生,要选择一门课程作为主修,主修flag里面写入 Y。只选择一门课程的学生,主修flag为N(实际上要是写入Y的话,就没有下面的麻烦事了,为了举例子,还请多多包含)。

现在我们要按照下面两个条件对这个表进行查询

只选修一门课程的人,返回那门课程的ID
选修多门课程的人,返回所选的主课程ID

简单的想法就是,执行两条不同的SQL语句进行查询。

条件1

--条件1:只选择了一门课程的学生
SELECT std_id, MAX(class_id) AS main_class
FROM Studentclass
GROUP BY std_id
HAVING COUNT(*) = 1;


执行结果1

STD_ID   MAIN_class
------   ----------
300      4
400      5
500      6


条件2

--条件2:选择多门课程的学生
SELECT std_id, class_id AS main_class
FROM Studentclass
WHERE main_class_flg = 'Y' ;


执行结果2

STD_ID  MAIN_class
------  ----------
100     1
200     3


如果使用Case函数,我们只要一条SQL语句就可以解决问题,具体如下所示

SELECT  std_id,
CASE WHEN COUNT(*) = 1  --只选择一门课程的学生的情况
THEN MAX(class_id)
ELSE MAX(CASE WHEN main_class_flg = 'Y'
THEN class_id
ELSE NULL END
)
END AS main_class
FROM Studentclass
GROUP BY std_id;


运行结果

STD_ID   MAIN_class
------   ----------
100      1
200      3
300      4
400      5
500      6


通过在Case函数中嵌套Case函数,在合计函数中使用Case函数等方法,我们可以轻松的解决这个问题。使用Case函数给我们带来了更大的自由度。

最后提醒一下使用Case函数的新手注意不要犯下面的错误

CASE col_1
WHEN 1        THEN 'Right'
WHEN NULL  THEN 'Wrong'
END


在这个语句中When Null这一行总是返回unknown,所以永远不会出现Wrong的情况。因为这句可以替换成WHEN col_1 = NULL,这是一个错误的用法,这个时候我们应该选择用WHEN col_1 IS NULL。

搞定SQL面试题---各种查询汇总案例

--一个题目涉及到的50个Sql语句
--(下面表的结构以给出,自己在数据库中建立表.并且添加相应的数据,数据要全面些. 其中Student表中,SId为学生的ID)

------------------------------------表结构--------------------------------------
--学生表tblStudent(编号StuId、姓名StuName、年龄StuAge、性别StuSex)
--课程表tblCourse(课程编号CourseId、课程名称CourseName、教师编号TeaId)
--成绩表tblScore(学生编号StuId、课程编号CourseId、成绩Score)
--教师表tblTeacher(教师编号TeaId、姓名TeaName)
---------------------------------------------------------------------------------

--问题:
--1、查询“001”课程比“002”课程成绩高的所有学生的学号;
Select StuId From tblStudent s1
Where (Select Score From tblScore t1 Where t1.StuId=s1.stuId And t1.CourseId='001')>
(Select Score From tblScore t2 Where t2.StuId=s1.stuId And t2.CourseId='002')

--2、查询平均成绩大于60分的同学的学号和平均成绩;

Select StuId,Avg(Score) as AvgScore From tblScore
Group By StuId
Having Avg(Score)>60

--3、查询所有同学的学号、姓名、选课数、总成绩;
Select StuId,StuName,
SelCourses=(Select Count(CourseId) From tblScore t1 Where t1.StuId=s1.StuId),
SumScore=(Select Sum(Score) From tblScore t2 Where t2.StuId=s1.StuId)
From tblStudent s1

--4、查询姓“李”的老师的个数;
Select Count(*) From tblTeacher Where TeaName like '李%'

--5、查询没学过“叶平”老师课的同学的学号、姓名;
Select StuId,StuName From tblStudent
Where StuId Not In
(
Select StuID From tblScore sc
Inner Join tblCourse cu ON sc.CourseId=cu.CourseId
Inner Join tblTeacher tc ON cu.TeaId=tc.TeaId
Where tc.TeaName='叶平'
)

--6、查询学过“001”并且也学过编号“002”课程的同学的学号、姓名;
Select StuId,StuName From tblStudent st
Where (Select Count(*) From tblScore s1 Where s1.StuId=st.StuId And s1.CourseId='001')>0
And
(Select Count(*) From tblScore s2 Where s2.StuId=st.StuId And s2.CourseId='002')>0

--7、查询学过“叶平”老师所教的所有课的同学的学号、姓名;
Select StuId,StuName From tblStudent st Where not exists
(
Select CourseID From tblCourse cu Inner Join tblTeacher tc On cu.TeaID=tc.TeaID
Where tc.TeaName='叶平' And CourseID not in
(Select CourseID From tblScore Where StuID=st.StuID)
)

--8、查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名;
Select StuId,StuName From tblStudent s1
Where (Select Score From tblScore t1 Where t1.StuId=s1.stuId And t1.CourseId='001')>
(Select Score From tblScore t2 Where t2.StuId=s1.stuId And t2.CourseId='002')

--9、查询所有课程成绩小于60分的同学的学号、姓名;
Select StuId,StuName From tblStudent st
Where StuId Not IN
(Select StuId From tblScore sc Where st.StuId=sc.StuId And Score>60)

--10、查询没有学全所有课的同学的学号、姓名;
Select StuId,StuName From tblStudent st
Where (Select Count(*) From tblScore sc Where st.StuId=sc.StuId)<
(Select Count(*) From tblCourse)

--11、查询至少有一门课与学号为“1001”的同学所学相同的同学的学号和姓名;
------运用连接查询
Select DistInct st.StuId,StuName From tblStudent st
Inner Join tblScore sc ON st.StuId=sc.StuId
Where sc.CourseId IN (Select CourseId From tblScore Where StuId='1001')
------嵌套子查询
Select StuId,StuName From tblStudent
Where StuId In
(
Select Distinct StuId From tblScore Where CourseId In (Select CourseId From tblScore Where StuId='1001')
)

--12、查询至少学过学号为“1001”同学所有课程的其他同学学号和姓名;
Select StuId,StuName From tblStudent
Where StuId In
(
Select Distinct StuId From tblScore Where CourseId Not In (Select CourseId From tblScore Where StuId='1001')

--13、把“SC”表中“叶平”老师教的课的成绩都更改为此课程的平均成绩; (从子查询中获取父查询中的表名,这样也行????)
--创建测试表
Select * Into Sc From tblScore
go

Update Sc Set Score=(Select Avg(Score) From tblScore s1 Where s1.CourseId=sc.CourseId)
Where CourseId IN
(Select CourseId From tblCourse cs INNER JOIN tblTeacher tc ON cs.TeaID=tc.TeaID WHERE TeaName ='叶平')

--14、查询和“1002”号的同学学习的课程完全相同的其他同学学号和姓名;
Select StuID,StuName From tblStudent st
Where StuId <> '1002'
And
Not Exists(Select * From tblScore sc Where sc.StuId=st.StuId And CourseId Not In (Select CourseId From tblScore Where StuId='1002'))
And
Not Exists(Select * From tblScore Where StuId='1002' And CourseId Not In (Select CourseId From tblScore sc Where sc.StuId=st.StuId))

--15、删除学习“叶平”老师课的SC表记录;
Delete From tblScore Where CourseId IN
(Select CourseId From tblCourse cs INNER JOIN tblTeacher tc ON cs.TeaId=tc.TeaId Where tc.TeaName='叶平')

--16、向SC表中插入一些记录,这些记录要求符合以下条件:没有上过编号“003”课程的同学学号、'002'号课的平均成绩;
Insert Into tblScore (StuId,CourseId,Score)
Select StuId,'002',(Select Avg(Score) From tblScore Where CourseId='002') From tblScore Where
StuId Not In (Select StuId From tblScore Where CourseId='003')

--17、按平均成绩从高到低显示所有学生的“数据库”、“企业管理”、“英语”三门的课程成绩,按如下形式显示: 学生ID,,数据库,企业管理,英语,有效课程数,有效平均分
Select StuId
,数据库=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='数据库' And sc.StuID=st.StuId)
,企业管理=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='企业管理' And sc.StuID=st.StuId)
,英语=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='英语' And sc.StuID=st.StuId)
,有效课程数=(Select Count(Score) From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where (CourseName='数据库' or CourseName='企业管理' or CourseName='英语') And sc.StuID=st.StuId)
,有效平均分=(Select Avg(Score) From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where (CourseName='数据库' or CourseName='企业管理' or CourseName='英语') And sc.StuID=st.StuId)
From tblStudent st
Order by 有效平均分 Desc

--18、查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分
Select CourseId as 课程ID, 最高分=(Select Max(Score) From tblScore sc Where sc.CourseId=cs.CourseId ),
最低分=(Select Min(Score) From tblScore sc Where sc.CourseId=cs.CourseId )
From tblCourse cs

--19、按各科平均成绩从低到高和及格率的百分数从高到低顺序 (百分数后如何格式化为两位小数??)
Select 课程ID,平均分,及格率 From
(Select CourseId as 课程ID, 平均分=(Select Avg(Score) From tblScore sc Where sc.CourseId=cs.CourseId ),
及格率=Convert(varchar(10),((Select Count(*) From tblScore sc Where sc.CourseId=cs.CourseId And sc.Score>=60)*10000/(Select Count(*) From tblScore sc Where sc.CourseId=cs.CourseId))/100)+'%'
From tblScore cs) as tmp
Group by 课程ID,平均分,及格率
Order by 平均分, Convert(float,substring(及格率,1,len(及格率)-1)) Desc

--20、查询如下课程平均成绩和及格率的百分数(用"1行"显示): 企业管理(001),马克思(002),OO&UML (003),数据库(004)
Select 课程ID=sc.CourseId,课程名称=cs.CourseName,平均成绩=Avg(Score)
,及格率 =Convert(varchar(10),((Select Count(Score) From tblScore Where CourseId=sc.CourseId And Score>=60)*10000/Count(Score))/100.0)+'%'
From tblScore sc
Inner Join tblCourse cs ON sc.CourseId=cs.CourseId
Where sc.CourseId like '00[1234]'
Group By sc.CourseId,cs.CourseName

--21、查询不同老师所教不同课程平均分从高到低显示
Select 课程ID=CourseId,课程名称=CourseName,授课教师=TeaName,平均成绩=(Select Avg(Score) From tblScore Where CourseId=cs.CourseId)
From tblCourse cs
Inner Join tblTeacher tc ON cs.TeaId=tc.TeaId
Order by 平均成绩 Desc

--22、查询如下课程成绩第 3 名到第 6 名的学生成绩单:企业管理(001),马克思(002),UML (003),数据库(004) 格式:[学生ID],[学生姓名],企业管理,马克思,UML,数据库,平均成绩
Select * From
(
Select Top 6 学生ID=StuId,学生姓名=StuName
,企业管理=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='企业管理' And sc.StuID=st.StuId)
,马克思=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='马克思' And sc.StuID=st.StuId)
,UML=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='UML' And sc.StuID=st.StuId)
,数据库=(Select Score From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where CourseName='数据库' And sc.StuID=st.StuId)
,平均成绩=(Select Avg(Score) From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where (CourseName='数据库' or CourseName='企业管理' or CourseName='UML'or CourseName='马克思') And sc.StuID=st.StuId)
,排名=Row_Number() Over(Order by(Select Avg(Score) From tblScore sc Inner Join tblCourse cs On sc.CourseId=cs.CourseId Where (CourseName='数据库' or CourseName='企业管理' or CourseName='UML'or CourseName='马克思') And sc.StuID=st.StuId) DESC)
From tblStudent st
Order by 排名
) as tmp
Where 排名 between 3 And 6

--23、统计列印各科成绩,各分数段人数:课程ID,课程名称,[100-85],[85-70],[70-60],[ <60]
Select 课程ID=CourseId, 课程名称=CourseName
,[100-85]=(Select Count(*) From tblScore sc Where CourseId=cs.CourseId And Score between 85 And 100)
,[85-70]=(Select Count(*) From tblScore sc Where CourseId=cs.CourseId And Score between 70 And 84)
,[70-60]=(Select Count(*) From tblScore sc Where CourseId=cs.CourseId And Score between 60 And 69)
,[<60]=(Select Count(*) From tblScore sc Where CourseId=cs.CourseId And Score <60)
From tblCourse cs

--24、查询学生平均成绩及其名次
Select 学号=st.StuId, 姓名=StuName,平均成绩=sc.AvgScore,名次=(Dense_Rank() Over(Order by sc.AvgScore Desc)) From tblStudent st
Inner Join (Select StuId,Avg(Score) as AvgScore From tblScore Group by StuId) as sc On sc.StuId=st.StuId
Order by 学号

--25、查询各科成绩前三名的记录:(不考虑成绩并列情况)
Select 学号=StuId,课程号=CourseId,分数=Score
From
(Select Row_Number() Over(order by CourseId,Score Desc) as i,* From tblScore) as tmp --得到一个临时的排名表,其中i表示编号
Where i In
(
Select Top 3 i From (Select Row_Number() Over(order by CourseId,Score Desc) as i,* From tblScore) as t1 Where t1.CourseId=tmp.CourseId
)

--26、查询每门课程被选修的学生数
Select 课程ID=CourseId,选修人数=(Select Count(*) From (Select Distinct StuId From tblScore Where CourseId=cs.CourseId) as tmp)
From tblCourse cs

--27、查询出只选修了一门课程的全部学生的学号和姓名
Select 学号=StuId,姓名=StuName
From tblStudent st
Where (Select Count(*) From (Select Distinct CourseId From tblScore Where StuId=st.StuId) as tmp)=1

--28、查询男生、女生人数
Select 男生人数=(select Count(*) From tblStudent Where StuSex='男'),
女生人数=(select Count(*) From tblStudent Where StuSex='女')

--29、查询姓“张”的学生名单
Select * From tblStudent Where StuName like '张%'
--30、查询同名同性学生名单,并统计同名人数
Select Distinct 学生姓名=StuName,同名人数=(Select Count(*) From tblStudent s2 Where s2.StuName=st.StuName) From tblStudent st
Where (Select Count(*) From tblStudent s2 Where s2.StuName=st.StuName)>=2

--31、1981年出生的学生名单(注:Student表中Sage列的类型是datetime)
Select * From tblStudent Where Year(Sage)=1981

--32、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列
Select 课程ID=CourseId,课程名称=CourseName,平均成绩=(Select Avg(Score) From tblScore Where CourseId=cs.CourseId)
From tblCourse cs
Order by 平均成绩,CourseId Desc

--33、查询平均成绩大于85的所有学生的学号、姓名和平均成绩
Select 学号=StuId,姓名=StuName,平均成绩=(Select Avg(Score) From tblScore Where StuId=st.StuId) From tblStudent st
Where (Select Avg(Score) From tblScore Where StuId=st.StuId)>85

--34、查询课程名称为“数据库”,且分数低于60的学生姓名和分数
Select 姓名=StuName,分数=Score From tblScore sc
Inner Join tblStudent st On sc.StuId=st.StuId
Inner Join tblCourse cs On sc.CourseId=cs.CourseId
Where CourseName='数据库' And Score<60

--35、查询所有学生的选课情况;
Select 学号=StuId,选课数=(Select Count(*) From (Select Distinct CourseId From tblScore Where StuId=st.StuId) as tmp)
From tblStudent st

Select distinct 姓名=StuName,选修课程=CourseName From tblScore sc
Inner Join tblStudent st On sc.StuId=st.StuId
Inner Join tblCourse cs On sc.CourseId=cs.CourseId

--36、查询任何一门课程成绩在70分以上的姓名、课程名称和分数;
Select 姓名=StuName,课程名称=CourseName,分数=Score From tblScore sc
Inner Join tblStudent st On sc.StuId=st.StuId
Inner Join tblCourse cs On sc.CourseId=cs.CourseId
Where Score>=70

--37、查询不及格的课程,并按课程号从大到小排列
Select * From tblScore Where Score<60 order by CourseId Desc

--38、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名;
Select StuId,StuName From tblStudent
Where StuId in
(Select StuId From tblScore Where CourseId='003' And Score>=80)

--39、求选了课程的学生人数
Select 选了课程的学生人数=Count(*) From tblStudent st Where StuId IN (Select StuID From tblScore)

--40、查询选修“叶平”老师所授课程的学生中,成绩最高的学生姓名及其成绩
Select CourseId,CourseName
,该科最高学生=(Select StuName From tblStudent Where StuId in (Select Top 1 StuID From tblScore Where CourseId=cs.CourseId Order by Score Desc))
,成绩=(Select Top 1 Score From tblScore Where CourseId=cs.CourseId Order by Score Desc)
From tblCourse cs Inner Join tblTeacher tc ON cs.TeaId=tc.TeaId
Where TeaName='叶平'

--41、查询各个课程及相应的选修人数
Select 课程ID=CourseId,选修人数=(Select Count(*) From (Select Distinct StuId From tblScore Where CourseId=cs.CourseId) as tmp)
From tblCourse cs

--42、查询不同课程成绩相同的学生的学号、课程号、学生成绩
Select 学号=StuId, 课程号=CourseId, 成绩=Score From tblScore sc
Where Exists (Select * From tblScore Where Score=sc.Score And StuId=sc.StuId And CourseId <>sc.CourseId)
Order by 学号,成绩

--43、查询每门功成绩最好的前两名
Select 课程号=CourseId,
第1名=(Select Top 1 StuId From tblScore Where CourseId=cs.CourseId Order by Score DESC),
第2名=(Select Top 1 StuID From (Select Top 2 StuId,Score From tblScore Where CourseId=cs.CourseId Order by Score DESC) as tmp Order by Score)
From tblCourse cs

--44、统计每门课程的学生选修人数(超过10人的课程才统计)。要求输出课程号和选修人数,查询结果按人数降序排列,若人数相同,按课程号升序排列
Select 课程ID=CourseId,选修人数=(Select Count(*) From (Select Distinct StuId From tblScore Where CourseId=cs.CourseId) as tmp)
From tblCourse cs
Where (Select Count(*) From (Select Distinct StuId From tblScore Where CourseId=cs.CourseId) as tmp)>=10
Order by 选修人数 DESC, 课程ID

--45、检索至少选修两门课程的学生学号
Select StuId from tblScore Group by Stuid having Count(*)>=2 --没有重复课程数据时可用此方法

--有重复课程时用此方法(如补考)
Select StuId from tblStudent st Where
(Select Count(*) From (Select Distinct CourseId From tblScore Where StuId=st.StuId) as tmp)>=2

--46、查询全部学生都选修的课程的课程号和课程名
Select CourseId,CourseName From tblCourse cs
Where Not Exists
(
Select * From tblStudent Where StuId Not In     --没学过本课程的学生是否存在
(Select StuId From tblScore Where CourseId=cs.CourseId)
)

--47、查询没学过“叶平”老师讲授的任一门课程的学生姓名
Select StuId,StuName From tblStudent
Where StuId Not In
(
Select StuID From tblScore sc
Inner Join tblCourse cu ON sc.CourseId=cu.CourseId
Inner Join tblTeacher tc ON cu.TeaId=tc.TeaId
Where tc.TeaName='叶平'
)

--48、查询两门以上不及格课程的同学的学号及其平均成绩
Select StuID as 学号,Avg(Score) as 平均成绩 From tblScore sc
Where (Select Count(*) From tblScore s1 Where s1.StuId=sc.StuId And Score<60)>=2
Group By StuId

--49、检索“004”课程分数小于60,按分数降序排列的同学学号 (ok)
Select StuID,Score From tblScore Where CourseId='004' And Score<60 Order by Score Desc

--50、删除“002”同学的“001”课程的成绩
Delete From SC Where StuId='1002' And CourseId='001'

----------------------SC为删除数据临时表
Select * INTO SC From tblScore
Select * from sc Where stuId='1018'
Insert Sc(Stuid,courseId,Score) Select StuID,'009',74 From tblStudent

/*********************************  建库建表建约束,插入测试数据  ******************************************/
Use master
go
if db_id('MySchool') is not null
Drop Database MySchool
Create Database MySchool
go
Use MySchool
go
create table tblStudent
(
StuId varchar(5) primary key,
StuName nvarchar(10) not null,
StuAge int,
StuSex nchar(1) not null
)
create table tblTeacher
(
TeaId varchar(3) primary key,
TeaName varchar(10) not null
)
create table tblCourse
(
CourseId varchar(3) primary key,
CourseName nvarchar(20) not null,
TeaId varchar(3) not null foreign key references tblTeacher(teaId)
)
create table tblScore
(
StuId varchar(5) not null foreign key references tblStudent(stuId),
CourseId varchar(3) not null foreign key references tblCourse(CourseId),
Score float
)
----------------------------------表结构----------------------------------------------------
--学生表tblStudent(编号StuId、姓名Stuname、年龄Stuage、性别Stusex)
--课程表tblCourse(课程编号CourseId、课程名称CourseName、教师编号TeaId)
--成绩表tblScore(学生编号StuId、课程编号CourseId、成绩Score)
--教师表tblTeacher(教师编号TeaId、姓名TeaName)
--------------------------------插入数据-------------------------------------------------
insert into tblStudent
select '1000','张无忌',18,'男' union
select '1001','周芷若',19,'女' union
select '1002','杨过',19,'男' union
select '1003','赵敏',18,'女' union
select '1004','小龙女',17,'女' union
select '1005','张三丰',18,'男' union
select '1006','令狐冲',19,'男' union
select '1007','任盈盈',20,'女' union
select '1008','岳灵珊',19,'女' union
select '1009','韦小宝',18,'男' union
select '1010','康敏',17,'女' union
select '1011','萧峰',19,'男' union
select '1012','黄蓉',18,'女' union
select '1013','郭靖',19,'男' union
select '1014','周伯通',19,'男' union
select '1015','瑛姑',20,'女' union
select '1016','李秋水',21,'女' union
select '1017','黄药师',18,'男' union
select '1018','李莫愁',18,'女' union
select '1019','冯默风',17,'男' union
select '1020','王重阳',17,'男' union
select '1021','郭襄',18,'女'
go

insert  into tblTeacher
select '001','姚明' union
select '002','叶平' union
select '003','叶开' union
select '004','孟星魂' union
select '005','独孤求败' union
select '006','裘千仞' union
select '007','裘千尺' union
select '008','赵志敬' union
select '009','阿紫' union
select '010','郭芙蓉' union
select '011','佟湘玉' union
select '012','白展堂' union
select '013','吕轻侯' union
select '014','李大嘴' union
select '015','花无缺' union
select '016','金不换' union
select '017','乔丹'
go

insert into tblCourse
select '001','企业管理','002' union
select '002','马克思','008' union
select '003','UML','006' union
select '004','数据库','007' union
select '005','逻辑电路','006' union
select '006','英语','003' union
select '007','电子电路','005' union
select '008','毛泽东思想概论','004' union
select '009','西方哲学史','012' union
select '010','线性代数','017' union
select '011','计算机基础','013' union
select '012','AUTO CAD制图','015' union
select '013','平面设计','011' union
select '014','Flash动漫','001' union
select '015','Java开发','009' union
select '016','C#基础','002' union
select '017','Oracl数据库原理','010'
go

insert into tblScore
select '1001','003',90 union
select '1001','002',87 union
select '1001','001',96 union
select '1001','010',85 union
select '1002','003',70 union
select '1002','002',87 union
select '1002','001',42 union
select '1002','010',65 union
select '1003','006',78 union
select '1003','003',70 union
select '1003','005',70 union
select '1003','001',32 union
select '1003','010',85 union
select '1003','011',21 union
select '1004','007',90 union
select '1004','002',87 union
select '1005','001',23 union
select '1006','015',85 union
select '1006','006',46 union
select '1006','003',59 union
select '1006','004',70 union
select '1006','001',99 union
select '1007','011',85 union
select '1007','006',84 union
select '1007','003',72 union
select '1007','002',87 union
select '1008','001',94 union
select '1008','012',85 union
select '1008','006',32 union
select '1009','003',90 union
select '1009','002',82 union
select '1009','001',96 union
select '1009','010',82 union
select '1009','008',92 union
select '1010','003',90 union
select '1010','002',87 union
select '1010','001',96 union

select '1011','009',24 union
select '1011','009',25 union

select '1012','003',30 union
select '1013','002',37 union
select '1013','001',16 union
select '1013','007',55 union
select '1013','006',42 union
select '1013','012',34 union
select '1000','004',16 union
select '1002','004',55 union
select '1004','004',42 union
select '1008','004',34 union
select '1013','016',86 union
select '1013','016',44 union
select '1000','014',75 union
select '1002','016',100 union
select '1004','001',83 union
select '1008','013',97
go


SQL常见面试题

sql常见面试题

sql理论题
1.触发器的作用?

答:触发器是一中特殊的存储过程,主要是通过事件来触发而被执行的。它可以强化约束,来维护数据的完整性和一致性,可以跟踪数据库内的操作从而不允许未经许可的更新和变化。可以联级运算。如,某表上的触发器上包含对另一个表的数据操作,而该操作又会导致该表触发器被触发。

2。什么是存储过程?用什么来调用?

答:存储过程是一个预编译的SQL语句,优点是允许模块化的设计,就是说只需创建一次,以后在该程序中就可以调用多次。如果某次操作需要执行多次SQL,使用存储过程比单纯SQL语句执行要快。可以用一个命令对象来调用存储过程。

3。索引的作用?和它的优点缺点是什么?
答:索引就一种特殊的查询表,数据库的搜索引擎可以利用它加速对数据的检索。它很类似与现实生活中书的目录,不需要查询整本书内容就可以找到想要的数据。索引可以是唯一的,创建索引允许指定单个列或者是多个列。缺点是它减慢了数据录入的速度,同时也增加了数据库的尺寸大小。

3。什么是内存泄漏?
答:一般我们所说的内存泄漏指的是堆内存的泄漏。堆内存是程序从堆中为其分配的,大小任意的,使用完后要显示释放内存。当应用程序用关键字new等创建对象时,就从堆中为它分配一块内存,使用完后程序调用free或者delete释放该内存,否则就说该内存就不能被使用,我们就说该内存被泄漏了。

4。维护数据库的完整性和一致性,你喜欢用触发器还是自写业务逻辑?为什么?

答:我是这样做的,尽可能使用约束,如check,主键,外键,非空字段等来约束,这样做效率最高,也最方便。其次是使用触发器,这种方法可以保证,无论什么业务系统访问数据库都可以保证数据的完整新和一致性。最后考虑的是自写业务逻辑,但这样做麻烦,编程复杂,效率低下。

5。什么是事务?什么是锁?
答:事务就是被绑定在一起作为一个逻辑工作单元的SQL语句分组,如果任何一个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是上有个节点。为了确保要么执行,要么不执行,就可以使用事务。要将有组语句作为事务考虑,就需要通过ACID测试,即原子性,一致性,隔离性和持久性。

锁:在所以的DBMS中,锁是实现事务的关键,锁可以保证事务的完整性和并发性。与现实生活中锁一样,它可以使某些数据的拥有者,在某段时间内不能使用某些数据或数据结构。当然锁还分级别的。

6。什么叫视图?游标是什么
答:视图是一种虚拟的表,具有和物理表相同的功能。可以对视图进行增,改,查,操作,试图通常是有一个表或者多个表的行或列的子集。对视图的修改不影响基本表。它使得我们获取数据更容易,相比多表查询。

游标:是对查询出来的结果集作为一个单元来有效的处理。游标可以定在该单元中的特定行,从结果集的当前行检索一行或多行。可以对结果集当前行做修改。一般不使用游标,但是需要逐条处理数据的时候,游标显得十分重要。

7。为管理业务培训信息,建立3个表:
S(S#,SN,SD,SA)S#,SN,SD,SA分别代表学号,学员姓名,所属单位,学员年龄
C(C#,CN)C#,CN分别代表课程编号,课程名称
SC(S#,C#,G) S#,C#,G分别代表学号,所选的课程编号,学习成绩
(1)使用标准SQL嵌套语句查询选修课程名称为’税收基础’的学员学号和姓名?
答案:select s# ,sn from s where S# in(select S# from c,sc where c.c#=sc.c# and cn=’税收基础’)
(2) 使用标准SQL嵌套语句查询选修课程编号为’C2’的学员姓名和所属单位?
答:select sn,sd from s,sc where s.s#=sc.s# and sc.c#=’c2’
(3) 使用标准SQL嵌套语句查询不选修课程编号为’C5’的学员姓名和所属单位?
答:select sn,sd from s where s# not in(select s# from sc where c#=’c5’)

(4)查询选修了课程的学员人数
答:select 学员人数=count(distinct s#) from sc

(5) 查询选修课程超过5门的学员学号和所属单位?
答:select sn,sd from s where s# in(select s# from sc group by s# having count(distinct c#)>5)

是查询A(ID,Name)表中第31至40条记录,ID作为主键可能是不是连续增长的列,完整的查询语句如下:

select top 10 * from A where ID >(select max(ID) from (select top 30 ID from A order by A

) T) order by A

要求是查询表A中存在ID重复三次以上的记录,完整的查询语句如下:
select * from(select count(ID) as count from table group by ID)T where T.count>3

create table testtable1
(
id int IDENTITY,
department varchar(12)
)

select * from testtable1
insert into testtable1 values('设计')
insert into testtable1 values('市场')
insert into testtable1 values('售后')
/*
结果
id department
1 设计
2 市场
3 售后
*/
create table testtable2
(
id int IDENTITY,
dptID int,
name varchar(12)
)
insert into testtable2 values(1,'张三')
insert into testtable2 values(1,'李四')
insert into testtable2 values(2,'王五')
insert into testtable2 values(3,'彭六')
insert into testtable2 values(4,'陈七')
/*
用一条SQL语句,怎么显示如下结果
id dptID department name
1 1 设计 张三
2 1 设计 李四
3 2 市场 王五
4 3 售后 彭六
5 4 黑人 陈七
*/

答案是:

SELECT testtable2.* , ISNULL(department,'黑人')
FROM testtable1 right join testtable2 on testtable2.dptID = testtable1.ID

在面试应聘的SQL Server数据库开发人员时,我运用了一套标准的基准技术问题。下面这些问题是我觉得能够真正有助于淘汰不合格应聘者的问题。它们按照从易到难的顺序排列。当你问到关于主键和外键的问题时,后面的问题都十分有难度,因为答案可能会更难解释和说明,尤其是在面试的情形下。

你能向我简要叙述一下SQL Server 2000中使用的一些数据库对象吗?

你希望听到的答案包括这样一些对象:表格、视图、用户定义的函数,以及存储过程;如果他们还能够提到像触发器这样的对象就更好了。如果应聘者不能回答这个基本的问题,那么这不是一个好兆头。

NULL是什么意思?
NULL(空)这个值是数据库世界里一个非常难缠的东西,所以有不少应聘者会在这个问题上跌跟头您也不要觉得意外。 NULL这个值表示UNKNOWN(未知):它不表示“”(空字符串)。假设您的SQL Server数据库里有ANSI_NULLS,当然在默认情况下会有,对NULL这个值的任何比较都会生产一个NULL值。您不能把任何值与一个 UNKNOWN值进行比较,并在逻辑上希望获得一个答案。您必须使用IS NULL操作符。

什么是索引?SQL Server 2000里有什么类型的索引?

任何有经验的数据库开发人员都应该能够很轻易地回答这个问题。一些经验不太多的开发人员能够回答这个问题,但是有些地方会说不清楚。简单地说,索引是一个数据结构,用来快速访问数据库表格或者视图里的数据。在SQL Server里,它们有两种形式:聚集索引和非聚集索引。聚集索引在索引的叶级保存数据。这意味着不论聚集索引里有表格的哪个(或哪些)字段,这些字段都会按顺序被保存在表格。由于存在这种排序,所以每个表格只会有一个聚集索引。非聚集索引在索引的叶级有一个行标识符。这个行标识符是一个指向磁盘上数据的指针。它允许每个表格有多个非聚集索引。

什么是主键?什么是外键?

主键是表格里的(一个或多个)字段,只用来定义表格里的行;主键里的值总是唯一的。外键是一个用来建立两个表格之间关系的约束。这种关系一般都涉及一个表格里的主键字段与另外一个表格(尽管可能是同一个表格)里的一系列相连的字段。那么这些相连的字段就是外键。

什么是触发器?SQL Server 2000有什么不同类型的触发器?

让未来的数据库开发人员知道可用的触发器类型以及如何实现它们是非常有益的。触发器是一种专用类型的存储过程,它被捆绑到SQL Server 2000的表格或者视图上。在SQL Server 2000里,有INSTEAD-OF和AFTER两种触发器。INSTEAD-OF触发器是替代数据操控语言(Data Manipulation

Language,DML)语句对表格执行语句的存储过程。例如,如果我有一个用于TableA的INSTEAD-OF-UPDATE

触发器,同时对这个表格执行一个更新语句,那么INSTEAD-OF-UPDATE触发器里的代码会执行,而不是我执行的更新语句则不会执行操作。

AFTER触发器要在DML语句在数据库里使用之后才执行。这些类型的触发器对于监视发生在数据库表格里的数据变化十分好用。

您如何确一个带有名为Fld1字段的TableB表格里只具有Fld1字段里的那些值,而这些值同时在名为TableA的表格的Fld1字段里?

这个与关系相关的问题有两个可能的答案。第一个答案(而且是您希望听到的答案)是使用外键限制。外键限制用来维护引用的完整性。它被用来确保表格里的字段只保存有已经在不同的(或者相同的)表格里的另一个字段里定义了的值。这个字段就是候选键(通常是另外一个表格的主键)。

另外一种答案是触发器。触发器可以被用来保证以另外一种方式实现与限制相同的作用,但是它非常难设置与维护,而且性能一般都很糟糕。由于这个原因,微软建议开发人员使用外键限制而不是触发器来维护引用的完整性。

对一个投入使用的在线事务处理表格有过多索引需要有什么样的性能考虑?

你正在寻找进行与数据操控有关的应聘人员。对一个表格的索引越多,数据库引擎用来更新、插入或者删除数据所需要的时间就越多,因为在数据操控发生的时候索引也必须要维护。

你可以用什么来确保表格里的字段只接受特定范围里的值?

这个问题可以用多种方式来回答,但是只有一个答案是“好”答案。您希望听到的回答是Check限制,它在数据库表格里被定义,用来限制输入该列的值。

触发器也可以被用来限制数据库表格里的字段能够接受的值,但是这种办法要求触发器在表格里被定义,这可能会在某些情况下影响到性能。因此,微软建议使用Check限制而不是其他的方式来限制域的完整性。

如果应聘者能够正确地回答这个问题,那么他的机会就非常大了,因为这表明他们具有使用存储过程的经验。

返回参数总是由存储过程返回,它用来表示存储过程是成功还是失败。返回参数总是INT数据类型。

OUTPUT参数明确要求由开发人员来指定,它可以返回其他类型的数据,例如字符型和数值型的值。(可以用作输出参数的数据类型是有一些限制的。)您可以在一个存储过程里使用多个OUTPUT参数,而您只能够使用一个返回参数。

什么是相关子查询?如何使用这些查询?

经验更加丰富的开发人员将能够准确地描述这种类型的查询。相关子查询是一种包含子查询的特殊类型的查询。查询里包含的子查询会真正请求外部查询的值,从而形成一个类似于循环的状况。

什么是SQL注入式攻击?
所谓SQL注入式攻击,就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。在某些表单中,用户输入的内容直接用来构造(或者影响)动态SQL命令,或作为存储过程的输入参数,这类表单特别容易受到SQL注入式攻击。常见的SQL注入式攻击过程类如:
⑴ 某个ASP.NET Web应用有一个登录页面,这个登录页面控制着用户是否有权访问应用,它要求用户输入一个名称和密码。
⑵ 登录页面中输入的内容将直接用来构造动态的SQL命令,或者直接用作存储过程的参数。下面是ASP.NET应用构造查询的一个例子:
System.Text.StringBuilder query = new System.Text.StringBuilder(

"SELECT * from Users WHERE login = '")

.Append(txtLogin.Text).Append("' AND password='")

.Append(txtPassword.Text).Append("'");

⑶ 攻击者在用户名字和密码输入框中输入"'或'1'='1"之类的内容。
⑷ 用户输入的内容提交给服务器之后,服务器运行上面的ASP.NET代码构造出查询用户的SQL命令,但由于攻击者输入的内容非常特殊,所以最后得到的SQL命令变成:SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'。
⑸ 服务器执行查询或存储过程,将用户输入的身份信息和服务器中保存的身份信息进行对比。
⑹ 由于SQL命令实际上已被注入式攻击修改,已经不能真正验证用户身份,所以系统会错误地授权给攻击者。
如果攻击者知道应用会将表单中输入的内容直接用于验证身份的查询,他就会尝试输入某些特殊的SQL字符串篡改查询改变其原来的功能,欺骗系统授予访问权限。
系统环境不同,攻击者可能造成的损害也不同,这主要由应用访问数据库的安全权限决定。如果用户的帐户具有管理员或其他比较高级的权限,攻击者就可能对数据库的表执行各种他想要做的操作,包括添加、删除或更新数据,甚至可能直接删除表
如何防范SQL注入式攻击?
好在要防止ASP.NET应用被SQL注入式攻击闯入并不是一件特别困难的事情,只要在利用表单输入的内容构造SQL命令之前,把所有输入内容过滤一番就可以了。过滤输入内容可以按多种方式进行。
⑴ 对于动态构造SQL查询的场合,可以使用下面的技术:
第一:替换单引号,即把所有单独出现的单引号改成两个单引号,防止攻击者修改SQL命令的含义。再来看前面的例子,"SELECT * from Users WHERE login = ''' or ''1''=''1' AND password = ''' or ''1''=''1'"显然会得到与"SELECT * from Users WHERE login = '' or '1'='1' AND password = '' or '1'='1'"不同的结果。
第二:删除用户输入内容中的所有连字符,防止攻击者构造出类如"SELECT * from Users WHERE login = 'mas' -- AND password =''"之类的查询,因为这类查询的后半部分已经被注释掉,不再有效,攻击者只要知道一个合法的用户登录名称,根本不需要知道用户的密码就可以顺利获得访问权限。
第三:对于用来执行查询的数据库帐户,限制其权限。用不同的用户帐户执行查询、插入、更新、删除操作。由于隔离了不同帐户可执行的操作,因而也就防止了原本用于执行SELECT命令的地方却被用于执行INSERT、UPDATE或DELETE命令。
⑵ 用存储过程来执行所有的查询。SQL参数的传递方式将防止攻击者利用单引号和连字符实施攻击。此外,它还使得数据库权限可以限制到只允许特定的存储过程执行,所有的用户输入必须遵从被调用的存储过程的安全上下文,这样就很难再发生注入式攻击了。
⑶ 限制表单或查询字符串输入的长度。如果用户的登录名字最多只有10个字符,那么不要认可表单中输入的10个以上的字符,这将大大增加攻击者在SQL命令中插入有害代码的难度。
⑷ 检查用户输入的合法性,确信输入的内容只包含合法的数据。数据检查应当在客户端和服务器端都执行——之所以要执行服务器端验证,是为了弥补客户端验证机制脆弱的安全性。
在客户端,攻击者完全有可能获得网页的源代码,修改验证合法性的脚本(或者直接删除脚本),然后将非法内容通过修改后的表单提交给服务器。因此,要保证验证操作确实已经执行,唯一的办法就是在服务器端也执行验证。你可以使用许多内建的验证对象,例如 RegularExpressionValidator,它们能够自动生成验证用的客户端脚本,当然你也可以插入服务器端的方法调用。如果找不到现成的验证对象,你可以通过CustomValidator自己创建一个。
⑸ 将用户登录名称、密码等数据加密保存。加密用户输入的数据,然后再将它与数据库中保存的数据比较,这相当于对用户输入的数据进行了"消毒"处理,用户输入的数据不再对数据库有任何特殊的意义,从而也就防止了攻击者注入SQL命令。 System.Web.Security.FormsAuthentication类有一个 HashPasswordForStoringInConfigFile,非常适合于对输入数据进行消毒处理。
⑹ 检查提取数据的查询所返回的记录数量。如果程序只要求返回一个记录,但实际返回的记录却超过一行,那就当作出错处理

Sql常见题目

为管理岗位业务培训信息,建立3个表:
S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号、学员姓名、所属单位、学员年龄
C (C#,CN ) C#,CN 分别代表课程编号、课程名称
SC ( S#,C#,G ) S#,C#,G 分别代表学号、所选修的课程编号、学习成绩
1. 使用标准SQL嵌套语句查询选修课程名称为’税收基础’的学员学号和姓名
--实现代码:
Select SN,SD FROM S Where [S#] IN( Select [S#] FROM C,SC Where C.[C#]=SC.[C#] AND CN=N'税收基础')
2. 使用标准SQL嵌套语句查询选修课程编号为’C2’的学员姓名和所属单位
--实现代码:
Select S.SN,S.SD FROM S,SC Where S.[S#]=SC.[S#] AND SC.[C#]='C2'
3. 使用标准SQL嵌套语句查询不选修课程编号为’C5’的学员姓名和所属单位
--实现代码:
Select SN,SD FROM S Where [S#] NOT IN( Select [S#] FROM SC Where [C#]='C5')
4. 使用标准SQL嵌套语句查询选修全部课程的学员姓名和所属单位
--实现代码:
Select SN,SD FROM S Where [S#] IN( Select [S#] FROM SC RIGHT JOIN C ON SC.[C#]=C.[C#] GROUP BY [S#] HAVING COUNT(*)=COUNT([S#]))
5. 查询选修了课程的学员人数
--实现代码:
Select 学员人数=COUNT(DISTINCT [S#]) FROM SC
6. 查询选修课程超过5门的学员学号和所属单位
--实现代码:
Select SN,SD FROM S Where [S#] IN( Select [S#] FROM SC GROUP BY [S#] HAVING COUNT(DISTINCT [C#])>5)
题目2:
问题描述:
S (SNO,SNAME) 学生关系。SNO 为学号,SNAME 为姓名
C (CNO,CNAME,CTEACHER) 课程关系。CNO 为课程号,CNAME 为课程名,CTEACHER 为任课教师
SC(SNO,CNO,SCGRADE) 选课关系。SCGRADE 为成绩
1. 找出没有选修过“李明”老师讲授课程的所有学生姓名
--实现代码:
Select SNAME FROM S Where NOT EXISTS( Select * FROM SC,C Where SC.CNO=C.CNO AND CNAME='李明' AND SC.SNO=S.SNO)
2. 列出有二门以上(含两门)不及格课程的学生姓名及其平均成绩
--实现代码:
Select S.SNO,S.SNAME,AVG_SCGRADE=AVG(SC.SCGRADE) FROM S,SC,( Select SNO FROM SC Where SCGRADE<60 GROUP BY SNO HAVING COUNT(DISTINCT CNO)>=2 )A Where S.SNO=A.SNO AND SC.SNO=A.SNO GROUP BY S.SNO,S.SNAME
3. 列出既学过“1”号课程,又学过“2”号课程的所有学生姓名
--实现代码:
Select S.SNO,S.SNAME FROM S,( Select SC.SNO FROM SC,C Where SC.CNO=C.CNO AND C.CNAME IN('1','2') GROUP BY SNO HAVING COUNT(DISTINCT CNO)=2 )SC Where S.SNO=SC.SNO
4. 列出“1”号课成绩比“2”号同学该门课成绩高的所有学生的学号
--实现代码:
Select S.SNO,S.SNAME FROM S,( Select SC1.SNO FROM SC SC1,C C1,SC SC2,C C2 Where SC1.CNO=C1.CNO AND C1.NAME='1' AND SC2.CNO=C2.CNO AND C2.NAME='2' AND SC1.SCGRADE>SC2.SCGRADE )SC Where S.SNO=SC.SNO
5. 列出“1”号课成绩比“2”号课成绩高的所有学生的学号及其“1”号课和“2”号课的成绩
--实现代码:
Select S.SNO,S.SNAME,SC.[1号课成绩],SC.[2号课成绩] FROM S,( Select SC1.SNO,[1号课成绩]=SC1.SCGRADE,[2号课成绩]=SC2.SCGRADE FROM SC SC1,C C1,SC SC2,C C2 Where SC1.CNO=C1.CNO AND C1.NAME='1' AND SC2.CNO=C2.CNO AND C2.NAME='2' AND SC1.SCGRADE>SC2.SCGRADE
)SC Where S.SNO=SC.SNO

求其中同一个号码的两次通话之间间隔大于10秒的通话记录ID
例如:6,7,8,9,10条记录均符合
ID 主叫号码 被叫号码 通话起始时间 通话结束时间 通话时长
1 98290000 0215466546656 2007-02-01 09:49:53.000 2007-02-01 09:50:16.000 23
2 98290000 021546654666 2007-02-01 09:50:29.000 2007-02-01 09:50:41.000 12
3 98290000 021546654666 2007-02-01 09:50:58.000 2007-02-01 09:51:12.000 14
4 68290900 0755133329866 2007-02-01 10:04:31.000 2007-02-01 10:07:13.000 162
5 78290000 0755255708638 2007-02-01 10:48:26.000 2007-02-01 10:49:23.000 57
6 78290000 0755821119109 2007-02-01 10:49:39.000 2007-02-01 10:52:55.000 196
7 78290000 035730928370 2007-02-01 11:30:45.000 2007-02-01 11:31:58.000 73
8 78290000 0871138889904 2007-02-01 11:33:47.000 2007-02-01 11:35:00.000 73
9 68290000 035730928379 2007-02-01 11:52:20.000 2007-02-01 11:54:56.000 156
10 68290000 0298521811199 2007-02-01 12:44:45.000 2007-02-01 12:45:04.000 19

答案:
SELECT DISTINCT a.* FROM dbo.hc a left join dbo.hc b
ON a.主叫号码=b.主叫号码
WHERE a.id<>b.id AND (DATEDIFF(second,a.通话起始时间,b.通话结束时间)>10 AND
DATEDIFF(second,b.通话起始时间,a.通话结束时间)>10)

Sql Server关于按周统计的问题
统计Sql Server里一个销售明细表里某个时间段的销售额,而且要按周进行比较,以下是该语句的写法:

select sum(销售金额), datename(week, 销售日期-1) from sales where 销售日期 betwee begindate and enddate group by datename(week, 销售日期-1)

注意:这里之所以要把销售日期-1是因为sql server默认的一周的第一天是星期天,而我们习惯的统计是以星期一到星期天计算的,所以减一。

SQL中的常用字符串处理方法

常用的字符串函数有:

  一、字符转换函数

  1、ASCII()

  返回字符表达式最左端字符的ASCII 码值。在ASCII()函数中,纯数字的字符串可不用‘’括起来,但含其它字符的字符串必须用‘’括起来使用,否则会出错。

  2、CHAR()

  将ASCII 码转换为字符。如果没有输入0 ~ 255 之间的ASCII 码值,CHAR() 返回NULL 。

  3、LOWER()和UPPER()

  LOWER()将字符串全部转为小写;UPPER()将字符串全部转为大写。

  4、STR()

  把数值型数据转换为字符型数据。

  STR ([,length[, ]])

  length 指定返回的字符串的长度,decimal 指定返回的小数位数。如果没有指定长度,缺省的length 值为10, decimal 缺省值为0。

  当length 或者decimal 为负值时,返回NULL;

  当length 小于小数点左边(包括符号位)的位数时,返回length 个*;

  先服从length ,再取decimal ;

  当返回的字符串位数小于length ,左边补足空格。

  二、去空格函数

  1、LTRIM() 把字符串头部的空格去掉。

  2、RTRIM() 把字符串尾部的空格去掉。

  三、取子串函数

  1、left()

  LEFT (, )

  返回character_expression 左起 integer_expression 个字符。

  2、RIGHT()

  RIGHT (, )

  返回character_expression 右起 integer_expression 个字符。

  3、SUBSTRING()

  SUBSTRING (, , length)

  返回从字符串左边第starting_ position 个字符起length个字符的部分。

  四、字符串比较函数

  1、CHARINDEX()

  返回字符串中某个指定的子串出现的开始位置。

  CHARINDEX (<’substring_expression’>, )

其中substring _expression 是所要查找的字符表达式,expression 可为字符串也可为列名表达式。如果没有发现子串,则返回0 值。

  此函数不能用于TEXT 和IMAGE 数据类型。

  2、PATINDEX()

  返回字符串中某个指定的子串出现的开始位置。

  PATINDEX (<’%substring _expression%’>, )其中子串表达式前后必须有百分号“%”否则返回值为0。

  与CHARINDEX 函数不同的是,PATINDEX函数的子串中可以使用通配符,且此函数可用于CHAR、 VARCHAR 和TEXT 数据类型。

  五、字符串操作函数

  1、QUOTENAME()

  返回被特定字符括起来的字符串。

  QUOTENAME (<’character_expression’>[, quote_ character]) 其中quote_ character 标明括字符串所用的字符,缺省值为“[]”。

  2、REPLICATE()

  返回一个重复character_expression 指定次数的字符串。

  REPLICATE (character_expression integer_expression) 如果integer_expression 值为负值,则返回NULL 。

  3、REVERSE()

  将指定的字符串的字符排列顺序颠倒。

  REVERSE () 其中character_expression 可以是字符串、常数或一个列的值。

  4、REPLACE()

  返回被替换了指定子串的字符串。

  REPLACE (, , ) 用string_expression3 替换在string_expression1 中的子串string_expression2。

  4、SPACE()

  返回一个有指定长度的空白字符串。

  SPACE () 如果integer_expression 值为负值,则返回NULL 。

  5、STUFF()

  用另一子串替换字符串指定位置、长度的子串。

  STUFF (, , ,)

  如果起始位置为负或长度值为负,或者起始位置大于character_expression1 的长度,则返回NULL 值。

如果length 长度大于character_expression1 中 start_ position 以右的长度,则character_expression1 只保留首字符。

  六、数据类型转换函数

  1、CAST()

  CAST ( AS [ length ])

  2、CONVERT()

  CONVERT ([ length ], [, style])

  1)data_type为SQL Server系统定义的数据类型,用户自定义的数据类型不能在此使用。

  2)length用于指定数据的长度,缺省值为30。

  3)把CHAR或VARCHAR类型转换为诸如INT或SAMLLINT这样的INTEGER类型、结果必须是带正号或负号的数值。

  4)TEXT类型到CHAR或VARCHAR类型转换最多为8000个字符,即CHAR或VARCHAR数据类型是最大长度。

  5)IMAGE类型存储的数据转换到BINARY或VARBINARY类型,最多为8000个字符。

  6)把整数值转换为MONEY或SMALLMONEY类型,按定义的国家的货币单位来处理,如人民币、美元、英镑等。

  7)BIT类型的转换把非零值转换为1,并仍以BIT类型存储。

  8)试图转换到不同长度的数据类型,会截短转换值并在转换值后显示“+”,以标识发生了这种截断。

  9)用CONVERT()函数的style 选项能以不同的格式显示日期和时间。style 是将DATATIME 和SMALLDATETIME 数据转换为字符串时所选用的由SQL Server 系统提供的转换样式编号,不同的样式编号有不同的输出格式。

  七、日期函数

  1、day(date_expression)

  返回date_expression中的日期值

  2、month(date_expression)

  返回date_expression中的月份值

  3、year(date_expression)

  返回date_expression中的年份值

  4、DATEADD()

  DATEADD (, , )

  返回指定日期date 加上指定的额外日期间隔number 产生的新日期。

  5、DATEDIFF()

  DATEDIFF (, , )

  返回两个指定日期在datepart 方面的不同之处,即date2 超过date1的差距值,其结果值是一个带有正负号的整数值。

  6、DATENAME()

  DATENAME (, )

  以字符串的形式返回日期的指定部分此部分。由datepart 来指定。

  7、DATEPART()

  DATEPART (, )

  以整数值的形式返回日期的指定部分。此部分由datepart 来指定。

  DATEPART (dd, date) 等同于DAY (date)

  DATEPART (mm, date) 等同于MONTH (date)

  DATEPART (yy, date) 等同于YEAR (date)

  8、GETDATE()

  以DATETIME 的缺省格式返回系统当前的日期和时间
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: