牛客网sql实战(三)

28.查找描述信息中包括robot的电影对应的分类名称以及电影数目,而且还需要该分类对应电影数量>=5部
不是很明白?
根据题意,需要有四张表

  • 题目所给的三张表:film,category,film_category
  • 另外需要一张每个分类对应的电影数量>=5的电影分类表
select c.name,count(*) from 
(select category_id from film_category
group by category_id having count(category_id)>=5) as a,
film as b,category as c,film_category as d
where b.film_id=d.film_id
and c.category_id=d.category_id
and a.category_id=d.category_id
and b.description like '%robot%';

29.使用join查询方式找出没有分类的电影id以及名称
本题不需要用到category表,将film表左连接film_category,再筛选出category_id为null的记录,即为没有分类的电影

select f.film_id,f.title from film as f left join film_category as fc
on f.film_id=fc.film_id where fc.category_id is null

30.使用子查询的方式找出属于Action分类的所有电影对应的title,description

  • 第一步:找到所有属于action分类的电影id
  • 第二步:根据得到的电影id得到对应的电影信息
-- 根据得到的电影id得到对应的电影信息
select title,description from film where film_id in(
-- 找到所有属于action分类的电影id
select fc.film_id from film_category as fc inner join category c on fc.category_id=c.category_id
where c.name='Action')

31.获取select * from employees对应的执行计划
explain

explain select * from employees;

32.将employees表的所有员工的last_name和first_name拼接起来作为Name,中间以一个空格区分
sqllite连接字符串的写法:

select last_name||" "||first_name as name  from employees

mysql下可以用concat:

select concat(last_name,' ',first_name) as name from employees;

33.创建一个actor表,包含如下列信息
注意:DEFAULT (datetime('now','localtime')) 设置默认值为系统的当前时间

create table actor(
    actor_id smallint(5) not null,
    first_name varchar(45) not null,
    last_name varchar(45) not null,
    last_update timestamp not null DEFAULT (datetime('now','localtime')),
    primary key(actor_id)
);

34.对于表actor批量插入如下数据

insert into actor(actor_id,first_name,last_name,last_update)values
(1,'PENELOPE','GUINESS','2006-02-15 12:34:33'),
(2,'NICK','WAHLBERG','2006-02-15 12:34:33')

35.对于表actor批量插入如下数据,如果数据已经存在,请忽略,不使用replace操作
sqllite3的做法:

insert or ignore into actor
values(3,'ED','CHASE','2006-02-15 12:34:33');

mysql的做法:

insert ignore into actor
values(3,'ED','CHASE','2006-02-15 12:34:33');

36.创建一个actor_name表,将actor表中的所有first_name以及last_name导入改表

create table actor_name as select first_name,last_name from actor;

37.针对如下表actor结构创建索引:
对first_name创建唯一索引uniq_idx_firstname,对last_name创建普通索引idx_lastname

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')))

解法:

create unique index uniq_idx_firstname on actor(first_name);
create index idx_lastname on actor(last_name);

38.针对actor表创建视图actor_name_view,只包含first_name以及last_name两列,并对这两列重新命名,first_name为first_name_v,last_name修改为last_name_v
方法一:

create view actor_name_view as 
select first_name as first_name_v,last_name as last_name_v
from actor;

方法二:

create view actor_name_view(first_name_v,last_name_v) as 
select first_name,last_name from actor;

知识点补充:

什么是视图?
视图是虚拟的表,与包含数据的表不一样,视图只包含使用时动态检索数据的查询
视图仅仅是用来查看存储在别处的数据的一种设施,本身不包含数据,因此返回的数据是从其他表中检索出来的,在添加或更改这些表中的数据时,视图将返回改变过的数据
视图的使用
create view 用于 创建视图
show create view viewname 查看创建视图的语句
drop view viewname删除视图
更新视图:方式1:先drop再create;方式2:create or replace view

39.针对salaries表emp_no字段创建索引idx_emp_no,查询emp_no为10005, 使用强制索引

sqllite的解法:

SELECT * FROM salaries INDEXED BY idx_emp_no WHERE emp_no = 10005

mysql的解法:

SELECT * FROM salaries FORCE INDEX (idx_emp_no) WHERE emp_no = 10005

存在actor表,包含如下列信息:
现在在last_update后面新增加一列名字为create_date, 类型为datetime, NOT NULL,默认值为'0000-00-00 00:00:00'

CREATE TABLE IF NOT EXISTS actor (
actor_id smallint(5) NOT NULL PRIMARY KEY,
first_name varchar(45) NOT NULL,
last_name varchar(45) NOT NULL,
last_update timestamp NOT NULL DEFAULT (datetime('now','localtime')));

解法:

alter table actor add create_date datetime not null default('0000-00-00 00:00:00');

注意:修改表中的记录使用update,更改表中的结构使用alter
40.构造一个触发器audit_log,在向employees_test表中插入一条数据的时候,触发插入相关的数据到audit中

create trigger audit_log after insert on employees_test
begin
insert into audit (EMP_no,NAME) values(NEW.ID,NEW.NAME);
end; 

知识点补充:
什么是触发器?

在某个表发生更改时自动处理,是mysql响应以下任意语句而自动执行的一条mysql语句

  • delete
  • insert
  • update

创建触发器的注意事项:

  • 唯一的触发器名
  • 触发器关联的表
  • 触发器应该响应的活动(delete、insert或update)
  • 触发器何时执行
    41.删除emp_no重复的记录,只保留最小的id对应的记录
delete from titles_test where id not in 
(select min(id) from titles_test group by emp_no)

42.将所有to_date为9999-01-01的全部更新为NULL,且 from_date更新为2001-01-01

update titles_test set to_date=null,from_date='2001-01-01' where to_date='9999-01-01'

43.将id=5以及emp_no=10001的行数据替换成id=5以及emp_no=10005,其他数据保持不变,使用replace实现。

update titles_test set emp_no=replace(emp_no,10001,10005) where id=5;

44.将titles_test表名修改为titles_2017

-- rename table titles_test to titles_2017;
ALTER TABLE titles_test RENAME TO titles_2017

45.在audit表上创建外键约束,其emp_no对应employees_test表的主键id

DROP TABLE audit;
CREATE TABLE audit(
    EMP_no INT NOT NULL,
    create_date datetime NOT NULL,
    FOREIGN KEY(EMP_no) REFERENCES employees_test(ID));

46.存在如下的视图:
create view emp_v as select * from employees where emp_no >10005;
如何获取emp_v和employees有相同的数据

select b.* from emp_v as a,employees as b where a.emp_no=b.emp_no

注意:需要在前加上表的显示,不然同时得到两张表的重复记录*
47.将所有获取奖金的员工当前的薪水增加10%。

update salaries set salary=salary*1.1 where emp_no in (
    select a.emp_no from emp_bonus as a inner join salaries as b on 
a.emp_no=b.emp_no and b.to_date='9999-01-01')

48.针对库中的所有表生成select count()对应的SQL语句*
sqlite写法:

select "select count(*) from "||name||";" as cnts
    from sqlite_master 
    where type='table';

mysql写法:

select concat("select count(*) from ",table_name,";") as cnts
from (select table_name from information_schema.columns) as new

49.将employees表中的所有员工的last_name和first_name通过(')连接起来
sqlite写法:

select last_name||"'"||first_name from employees;

mysql写法:

select concat(last_name,"'",first_name) from employees;

50.查找字符串'10,A,B' 中逗号','出现的次数cnt

select (length('10,A,B')-length(replace('10,A,B',',','')))/length(',') as cnt

51.获取Employees中的first_name,查询按照first_name最后两个字母,按照升序进行排列

  • substr语法:参数一:目标串;参数二:+表示从左往右数,-表示从右往左数;参数三:截取的长度
select first_name from employees order by substr(first_name,-2,2)

52.按照dept_no进行汇总,属于同一个部门的emp_no按照逗号进行连接,结果给出dept_no以及连接出的结果employees

select dept_no,group_concat(emp_no,',') from dept_emp
group by dept_no

53.查找排除当前最大、最小salary之后的员工的平均工资avg_salary

select avg(salary) as avg_salary from salaries where to_date='9999-01-01'
and salary<>(select min(salary) from salaries where to_date='9999-01-01')
and salary<>(select max(salary) from salaries where to_date='9999-01-01');

54.分页查询employees表,每5行一页,返回第2页的数据

select * from employees limit 5,5

55.获取所有员工的emp_no、部门编号dept_no以及对应的bonus类型btype和received ,没有分配具体的员工不显示

  • 先得到分配了部门的员工信息与部门信息的表,使用内连接
  • 在将上表与bonus表进行左连接,没有bonus信息的地方不显示
select a.emp_no,b.dept_no,c.btype,c.recevied 
from employees as a 
inner join dept_emp as b on a.emp_no=b.emp_no
left join emp_bonus as c on a.emp_no=c.emp_no;

56.使用含有关键字exists查找未分配具体部门的员工的所有信息

select a.* from employees as a where not exists 
(select emp_no from dept_emp where emp_no=a.emp_no)

57.给出emp_no、first_name、last_name、奖金类型btype、对应的当前薪水情况salary以及奖金金额bonus。 bonus类型btype为1其奖金为薪水salary的10%,btype为2其奖金为薪水的20%,其他类型均为薪水的30%。

case语句的使用:

case (条件变量)
when (条件值一) then (内容)
when (条件值二) then (内容)
、、、
else (内容) end

select a.emp_no,a.first_name,a.last_name,b.btype,c.salary,
(case b.btype
 when 1 then c.salary*0.1
 when 2 then c.salary*0.2
 else c.salary*0.3 end
)as bonus
from employees as a 
inner join emp_bonus as b 
on a.emp_no=b.emp_no
inner join salaries as c on a.emp_no=c.emp_no
where c.to_date='9999-01-01'

58.按照salary的累计和running_total,其中running_total为前两个员工的salary累计和

select a.emp_no,a.salary,
(select sum(b.salary) from salaries as b 
 where b.emp_no<=a.emp_no and b.to_date='9999-01-01') 
as running_total 
from salaries as a 
where a.to_date='9999-01-01' order by a.emp_no; 

59.对于employees表中,给出奇数行的first_name

  • 按照first_name排序,确定行号?如何确定?生成一个新表,其中小于当前first_name的记录个数即为按first_name排序后的行号
  • 利用where语句筛选出行号为奇数的记录
select e1.first_name from 
    (select e2.first_name,(
            select count(*) from employees as e3 where e3.first_name<=e2.first_name
        )as row_id from employees as e2
    ) as e1
where e1.row_id&1=1

你可能感兴趣的:(牛客网sql实战(三))