牛客网SQL题目解析(答案+解析+理解)

2023-10-28

本文记录了牛客网sql全部题目的答案与难题解析,部分题目包含多种解法,并且涵盖了开窗函数等各种语法点的理解

标题中高亮的题目,是易错题

牛客网刷题链接:牛客网sql在线练习
本文所有语句使用mysql8.0

参考教程资源:

mysql教程1

mysql教程2

1.where+子查询

select * from employees
    order by hire_date desc
    limit 0,1;
    
    
select 
* 
from employees
where hire_date = 
    (
         select 
         max(hire_date) 
         from employees
    )
  • limit m,n 从m+1处开始,返回n行,m可以省略
  • 使用子查询的方法比较准确

2limit倒数第n个

select
*
from employees
where hire_date = 
    (
        select 
         distinct hire_date 
         from employees
        order by hire_date desc
        limit 2,1
    )
  • 注意使用distinct进行去重

3简单表连接

  1. select
    b.*,a.dept_no
    from dept_manager a left join salaries b
    on a.emp_no = b.emp_no
    where a.to_date='9999-01-01'
    and b.to_date='9999-01-01'
    ORDER BY b.emp_no
    
    • 注意过滤掉已经离职的领导

4内连接inner join

  select last_name
  ,first_name
  ,dept_no
  from employees inner join dept_emp
  on employees.emp_no = dept_emp.emp_no
  • 注意使用内连接
  • 注意连接时,大表(数据量多的表要放在前面)

5 左连接

select last_name
,first_name
,dept_no
from employees left join dept_emp
on employees.emp_no = dept_emp.emp_no

7简单分组

  -- 筛选变动次数超过15次的员工
  select 
  emp_no
  ,count()
  from salaries
  group by emp_no
  having count()>15
  
  -- 筛选加薪次数超过15次的员工
  select 
  a.emp_no
  , count(*) as t
  from salaries a 
  inner join salaries b
  on a.emp_no=b.emp_no
  where a.salaries < b.salaries
  group by a.emp_no
  having t>15
  • 在第二个语句中,使用了自连接来,筛选出加薪的员工
  • 当遇到一个同个字段进行比较时,应该使用自连接

8结果去重distinct或group by

  --使用distinct进行去重
  select 
  distinct salary
  from salaries
  where to_date = '9999-01-01'
  order by salary desc
  
  -- 使用groupby进行去重
  select 
  salary
  from salaries
  where to_date = '9999-01-01'
  group by salary
  order by salary desc
  • 当数据量较大时,建议使用groupby进行去重
  • distinct会将select之后的所有字段合并进行去重
  • group by 和distinct在去重的时候,都会包含null,将所有的null看作一个组

10null判断

  -- 使用join+is null
  select
  employees.emp_no
  from employees 
  left join dept_manager
  on employees.emp_no = dept_manager.emp_no
  where dept_manager.dept_no is  null
  
  -- 使用子查询
  SELECT emp_no FROM employees
  WHERE emp_no NOT IN (SELECT emp_no FROM dept_manager)
  • 判断非空时,应该使用is null / is not null,不能使用!=null
  • 连接的性能要高于子查询,尽量使用连接而不是子查询

11简单表连接

    select 
    a.emp_no
    ,b.emp_no
    from dept_emp a inner join dept_manager b
    on a.dept_no = b.dept_no
    where a.emp_no != b.emp_no
    and a.to_date = '9999-01-01' 
    AND b.to_date = '9999-01-01'

12求分组字段最大值的信息

  • 方法1
    -- 使用子查询方法
    select
    d1.dept_no
    ,d1.emp_no
    ,s1.salary
    from salaries s1 inner join dept_emp d1
    on s1.emp_no = d1.emp_no
    AND d1.to_date='9999-01-01'
    AND s1.to_date='9999-01-01'
    where s1.salary in 
     (
         select max(s2.salary)
         from salaries s2 inner join dept_emp d2
         on s2.emp_no = d2.emp_no
         AND d2.to_date='9999-01-01'
         AND s2.to_date='9999-01-01'
         AND d2.dept_no = d1.dept_no -- 利用内查询获取外查询的部门编号
     )
    order by d1.dept_no asc
    
  • 方法2

    
    -- 使用开窗函数
    select
    t.dept_no
    ,t.emp_no
    ,t.salary
    from
        (
            select
            d.dept_no
            ,d.emp_no
            ,s.salary
            ,dense_rank() over (partition by d.dept_no order by s.salary desc) as rk
            from dept_emp d inner join salaries s
            on d.emp_no = s.emp_no
            where d.to_date='9999-01-01'
            and s.to_date='9999-01-01'
        ) t
    where t.rk = 1
    
    • 开窗函数使用方法链接
    • dense_rank() 对每个dept_no部门中的partition分组数据进行排序
    • row_number(),rank(),ntile(n),以及其他聚合函数

15奇数判断

  1. select
    *
    

from employees
where emp_no%2=1
and last_name != ‘Mary’
order by hire_date desc
```

  • 不等于的几种表示方法
    • !=
    • is not
    • <>
  • 奇数的表示方法
    • x%2=1
    • x&1 使用了位运算

16简单分组

select 
title
,avg(salary)as avg_salary
from salaries s inner join titles t
on s.emp_no = t.emp_no
where s.to_date='9999-01-01'
group by title
order by avg_salary

17排序取第n个值(order by + limit)

select 
emp_no
,salary
from salaries
order by salary desc
limit 1,1

18使用子查询或自连接进行排序

-- 使用子查询
select 
s.emp_no
,s.salary
,e.last_name
,e.first_name
from employees e 
inner join salaries s
on e.emp_no = s.emp_no
where s.salary = 
    (
        select 
        max(salary)  -- 2 第二高工资
        from salaries
        where salary<>
        (
            select max(salary) -- 1查出最高工资
            from salaries
            where to_date='9999-01-01'
        )
    )
and s.to_date = '9999-01-01'

-- 使用自连接
select s.emp_no
, s.salary
, e.last_name
, e.first_name
from salaries s 
join employees e
on s.emp_no = e.emp_no
where s.salary =
    (
        select s1.salary
        from salaries s1 join salaries s2      -- 自连接查询
        on s1.salary <= s2.salary
        group by s1.salary                     -- 当s1<=s2链接并以s1.salary分组时一个s1会对应多个s2
        having count(distinct s2.salary) = 2   -- (去重之后的数量就是对应的名次)
    )
and s.to_date = '9999-01-01'
  • 当不使用order by 时,可以使用自连接或者多个子查询

19 三表连接

select last_name
,first_name
,dept_name
from employees e 
left join dept_emp d
on e.emp_no = d.emp_no
left join departments 
on d.dept_no = departments.dept_no
  • 多表连接时的执行顺序: 链接链接

  • 多表连接的时候,数据库内部执行的顺序,可能并不是我们写的顺序

21筛选某一字段的变化

select
a.emp_no
,b.salary - a.salary as growth
from salaries a 
inner join employees e
    on e.emp_no=a.emp_no
    and e.hire_date = a.from_date
inner join salaries b
    on a.emp_no = b.emp_no
where b.to_date= '9999-01-01'
order by growth
  • 第一次join筛选出入职时的工资

  • 第二次自连接筛选出,通过where筛选出当前的工资

22简单连接+分组

select 
de.dept_no
,de.dept_name
,count(*) as sum
from salaries s
join dept_emp d
    on s.emp_no = d.emp_no
right join departments de
    on d.dept_no = de.dept_no
group by de.dept_name,de.dept_no
order by de.dept_no
  • 是用两次表连接
  • 使用groupby 进行分组

23窗口函数

select
emp_no
,salary
,dense_rank() over(order by salary desc) t_rank
from salaries
order by t_rank,emp_no
  • 使用一个开窗函数来统计排名,相等的看作一个排名

24简单连接

select 
d.dept_no
,d.emp_no
,s.salary
from salaries s
join dept_emp d
    on s.emp_no = d.emp_no
    and s.to_date = '9999-01-01'
where s.emp_no not in 
    (
        select
        emp_no
        from dept_manager de
        where de.to_date = '9999-01-01'
    )

25多表复用

select
emp_no
,manager_no
,emp_salary
,manager_salary
from 
    (
        select 
        s1.emp_no as emp_no
        ,s1.salary as emp_salary
        ,dep1.dept_no
        from salaries s1 
        join dept_emp dep1
        on s1.emp_no = dep1.emp_no
        where s1.emp_no not in 
            (
                select emp_no
                from dept_manager der
                where der.to_date = '9999-01-01'
            )
        and s1.to_date = '9999-01-01'
    )tem1-- 非领导的工资
join 
    (
        select 
        s2.emp_no as manager_no
        ,s2.salary as manager_salary
        ,dep2.dept_no
        from salaries s2
        join dept_emp dep2
            on dep2.emp_no = s2.emp_no 
        where s2.emp_no in 
            (
                select emp_no
                from dept_manager der
                where der.to_date = '9999-01-01'
            )
        and s2.to_date = '9999-01-01'
    ) tem2 -- 部门领导的工资
on tem1.dept_no = tem2.dept_no -- 按部门进行连接
where emp_salary>manager_salary -- 筛选工资高低
select de.emp_no,
       dm.emp_no as manager_no,
       s1.salary as emp_salary,
       s2.salary as manager_salary
from dept_emp de,dept_manager dm,salaries s1,salaries s2
where de.dept_no=dm.dept_no
and de.emp_no=s1.emp_no
and dm.emp_no=s2.emp_no
and s1.to_date='9999-01-01'
and s2.to_date='9999-01-01'
and s1.salary>s2.salary
  • 使用多表复用可以将多个子查询融合在一起,减少代码量

26简单分组

select de.dept_no
,dep.dept_name
,title
,count(*)
from dept_emp de
join titles ti
    on ti.emp_no = de.emp_no
    and de.to_date = '9999-01-01'
join departments dep
    on de.dept_no = dep.dept_no
group by de.dept_no,title
order by de.dept_no

28虚表的使用

select 
c.name
,count(f.film_id) as film_num
from film_category fc 
join category c
    on fc.category_id = c.category_id
join film f
    on fc.film_id = f.film_id
where f.description like '%robot%'
and fc.category_id in 
    (
        select category_id
        from film_category
        group by category_id
        having count(*)>=5
    )
group by c.name

  • 使用子查询来约束类别,保证类别的电影数量>=5
SELECT 
c.name
, COUNT(fc.film_id) 
FROM
 	(
        select 
        category_id
        , COUNT(film_id) AS category_num 
        FROM film_category  
        GROUP BY category_id 
        HAVING count(film_id)>=5
    )  AS cc
	,film AS f
	, film_category AS fc
	, category AS c
WHERE  f.description LIKE '%robot%'
AND f.film_id = fc.film_id
AND c.category_id = fc.category_id
AND c.category_id=cc.category_id
  • 使用虚表来限制电影类别

29on和where

select
f.film_id
,title
from film f 
left join film_category fc
    on f.film_id = fc.film_id
where category_id is null
  • 注意on和where的执行顺序,把条件放在on上,会得出不正确的结果
  • 当条件放在on上时,条件会和连接字段同时计算,从而导致结果不正确

30简单查询

select
title
,description
from film f
join film_category fc
    on f.film_id = fc.film_id
join category c
    on c.category_id = fc.category_id
where name = 'Action'

32 concat字符串拼接

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

33 创建表

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 date not null default current_timestamp -- 设置默认时间
        )
  • 当前日期:CURDATE(),CURRENT_DATE

  • 当前时间:now()语句开始执行的时间,sysdate()语句执行到的时间

34批量插入

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')

35ignore insert

insert ignore into actor(
                   actor_id
                    ,first_name
                    ,last_name
                    ,last_update)
values 
    (
        '3','ED','CHASE','2006-02-15 12:34:33'
    )
    
  • insert into:插入数据,如果主键重复,则报错
  • insert repalce:插入替换数据,如果存在主键或unique数据则替换数据
  • insert ignore:如果存在主键或unique数据,则不进行insert。

36select insert

create table if not exists actor_name
(
    first_name varchar(45) not null comment '名称',
    last_name varchar(45) not null comment '姓氏'
);

insert into actor_name(first_name
                      ,last_name)
(select
    first_name
    ,last_name
    from actor )
  • 注意同时执行多条语句时,要加“ ;”号

37创建索引

alter table actor
add unique index uniq_idx_firstname(first_name);
alter table actor
add index idx_lastname(last_name)
-- 1通过create创建索引
CREATE [UNIQUE|FULLTEXT|SPATIAL] INDEX index_name
USING [BTREE | HASH | RTREE] -- 索引数据类型,可以省略
ON table_name (column_name [(length)] [ASC | DESC],...) -- 可以添加多个字段,并指定排序方式
-- 索引的类型 PRIMARY KEY,KEY,UNIQUE或INDEX,当创建表时,若声明了主键或者unique,会自动生成索引

-- 2 通过alter table创建索引
ALTER TABLE tbl_name ADD [PRIMARY KEY/UNIQUE INDEX indexname/fulltext indexname] (col_list);

-- 3删除索引
DROP INDEX index_name ON tbl_name;
// 或者
ALTER TABLE tbl_name DROP INDEX index_name;
ALTER TABLE tbl_name DROP PRIMARY KEY;

38创建视图

CREATE VIEW actor_name_view 
AS
    SELECT first_name as first_name_v
    , last_name as last_name_v
    FROM actor
CREATE 
   [ALGORITHM = {MERGE  | TEMPTABLE | UNDEFINED}]
VIEW [database_name].[view_name] 
AS
	[SELECT  statement]
-- 使用条件:
-- SELECT语句可以在WHERE子句中包含子查询,但FROM子句中的不能包含子查询。
-- SELECT语句不能引用任何变量,包括局部变量,用户变量和会话变量。
-- SELECT语句不能引用准备语句的参数。

39强制索引

SELECT 
* 
FROM salaries 
FORCE INDEX(idx_emp_no )
WHERE emp_no = 10005
  • 使用FORCE INDEX(idx_name )可以指定查询时使用的索引

40增加一列

alter table actor
add column create_date datetime not null default '2020-10-1 00:00:00'

41创建触发器

create trigger audit_log 
after insert
on employees_test
for each row
begin
    insert into audit(EMP_no,NAME)
    values(NEW.ID,NEW.NAME);-- 注意加分号,表示语句的结束
end
  • 触发器创建:链接
  • 在触发语句中,使用new指代插入、更新后的行
  • old代表更新或者删除的行

42条件删除

delete 
from titles_test
where id not in
    (
        select id
        from
        (
            select min(id) as id
            from titles_test
            group by emp_no
        ) as a
    )
  • 注意,在删除或者跟更新时,条件中的子查询不能使用更新或者删除的表本身,必须使用别名的方式,将子查询存储为新表

  • DELETE FROM customers
    WHERE country = 'France'
    ORDER BY creditLimit
    LIMIT 5;
    
  • 使用order by 和limit也可以约束删除的范围

  • 当删除表中全部数据时,使用truncate table table_name更加高效

43更新表

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

44 更新表(使用replace函数)

UPDATE titles_test
SET emp_no = 
    REPLACE(emp_no, 10001, 10005)
WHERE id = 5
replace into titles_test
select
5
, 10005
, title
, from_date
, to_date
from titles_test
where id = 5;
  1. 类似与insert
REPLACE INTO table_name(column_list)
VALUES(value_list)
  1. 类似于update
REPLACE INTO table
SET column1 = value1,
    column2 = value2
  1. insert select
REPLACE INTO cities(name,population)
SELECT name,population FROM cities 
WHERE id = 1

45alter的使用

alter table titles_test
rename to titles_2017
  • alter的常用方法:

  • ALTER TABLE 表名 ADD 列名/索引/主键/外键等;

  • ALTER TABLE 表名 DROP 列名/索引/主键/外键等;

  • ALTER TABLE 表名 ALTER 仅用来改变某列的默认值;

  • ALTER TABLE 表名 RENAME 列名/索引名 TO 新的列名/新索引名;

  • ALTER TABLE 表名 RENAME TO/AS 新表名;

  • ALTER TABLE 表名 MODIFY 列的定义但不改变列名;

  • ALTER TABLE 表名 CHANGE 列名和定义都可以改变。

46 外键

alter table audit
add foreign key fk (emp_no)
references employees_test(id)

外键简介:https://www.yiibai.com/mysql/foreign-key.html

外键约束语法:

CONSTRAINT constraint_name 
FOREIGN KEY foreign_key_name (columns) 
REFERENCES parent_table(columns) 
ON DELETE action 
ON UPDATE action

action可以是CASCADE创建级联删除或者级联更新

action是RESTRICT或者no action时,不允许删除或者更新

action是SET NULL时,删除或更新父表时,子表被设置为null

48条件更新

update salaries
set
    salary=1.1*salary
where
    to_date = '9999-01-01'
and emp_no in
    (
        select emp_no
        from emp_bonus
    )

50字符串拼接

select concat(last_name,'\'',first_name)
from employees

51字符串长度与替换

select 
char_length('A,10,B')- char_length(
    replace('10,A,B',',','')
);
  • 使用length统计字符串长度时,统计的是字节长度,当编码不同时,容易出错,使用char_length更加准确

52截取字符串

select first_name
from employees
order by right(first_name,2)	
  • 常见的字符串函数

  • 字符串处理函数

    • 大小写;

    ​ Lower(列名)

    ​ Upper(列名)

    • 字符串定位

    ​ POSITION(字符 IN 列名) mysql

    ​ PATINDEX(’%s1%’, s2) sqlserver

    • 合并

    ​ CONCAT(列名, ’ is in ', 列名…)

    • 替换

    ​ replace(列名,旧字符串,新字符串)

    • 取左

    ​ left (列名,位数) 返回字符串列中左边多少位的字符

    • 匹配单引号等特殊字符

    ​ 使用转义字符+特殊字符

    • 提取字符串

    ​ SUBSTRING(列名 , 开始位 ,字符长度 ) mysql

53分组字符串拼接

select
dept_no
,group_concat(emp_no separator ',')
from dept_emp
group by dept_no
order by dept_no
  • group_concat函数使用方法:链接

  • 使用语法:

  • GROUP_CONCAT(DISTINCT expression
        ORDER BY expression
        SEPARATOR sep);
    

    按照orderby的顺序,用sep分隔符,连接每个group中的字符串

54剔除最大最小值

select 
avg(salary) as avg_salary
from salaries
where to_date = '9999-01-01'
and salary not in
    (
        select 
        max(salary)
        from salaries
        where to_date = '9999-01-01'
    )
and salary not in
    (
        select 
        min(salary)
        from salaries
        where to_date = '9999-01-01'
    )
  • 使用聚合函数
SELECT (SUM(salary) - MAX(salary) - MIN(salary)) / (COUNT(1)-2) avg_salary 
FROM salaries 
where to_date = '9999-01-01';

55 分页显示

select 
*
from
employees
order by emp_no
limit 5,5
  • limit 每页显示数量*(第n页 -1),每页显示数量

56多表连接

select
distinct
e.emp_no
,d.dept_no
,btype
,received
from employees e
inner join dept_emp d
    on e.emp_no = d.emp_no
left join emp_bonus b
    on d.emp_no = b.emp_no

57exists

select
* 
from employees e
where
    not exists
    (
        select *
        from dept_emp d
        where d.emp_no = e.emp_no
    )
  • exists和in通常可以实现相同的功能
  • 当从表(子查询的表)很大时,通常使用in

59case语句

select
b.emp_no
,first_name
,last_name
,btype
,salary
, case when btype = 1 
            then salary*0.1
       when btype = 2 
            then salary*0.2
        else salary * 0.3
    end
    as bonus
from emp_bonus b
left join employees e
    on b.emp_no = e.emp_no
join salaries s
    on e.emp_no = s.emp_no
where s.to_date = '9999-01-01'
  • case语法

  • CASE  case_expression
       WHEN when_expression_1 THEN commands
       WHEN when_expression_2 THEN commands
       ...
       ELSE commands
    END CASE
    
    

60累计和

select emp_no
,salary
,sum(salary) over(order by emp_no) as running_total
from salaries
where to_date = '9999-01-01'
  • 累计和求法:sum(xx) over (order by xx)

61开窗函数排序

SELECT
    e.first_name
FROM employees e JOIN
(
    SELECT 
        first_name
        , ROW_NUMBER() OVER(ORDER BY first_name ASC) AS  r_num
    FROM employees
) AS t 
ON e.first_name = t.first_name
WHERE t.r_num % 2 = 1;

62分组筛选

select
number
from
grade
group by number
having count(*)>2

63开窗函数排序

select
id
,number
,dense_rank() over(order by number desc) as t_rank
from passing_number
order by t_rank,id
  • 不要忘记over函数后的排序方式desc

64左连接

select
p.id
,name
,content
from person p
left join task t
on p.id = t.person_id

65case与avg求组内某个字段数值比例

select
e.date
, round(AVG(
                case e.type when 'no_completed' then 1
                else 0
                end
            )
        ,3
       )as p
from email e 
join `user` u1
    on e.receive_id = u1.id
join `user` u2
    on e.send_id = u2.id
where u1.is_blacklist = 0
    and u2.is_blacklist = 0
group by e.date
order by e.date

66开窗函数与分组

select 
user_id
,max(`date`) as d
from login
group by user_id
order by user_id
  • 使用开窗函数
select distinct
    user_id,
    last_value(date) 
        over(partition by user_id -- 按照user_id进行分组
             order by date -- 组内按照date进行排序
             rows between current row and unbounded following -- 计算时,从当前行到组内最后一行
            ) as d
from login;
window_function_name(expression) 
    OVER (
        [partition_defintion]
        [order_definition]
        [frame_definition]
    ) 

frame_definition就是在partition内,取每一行的时候,在组内计算时,选择的计算范围


image-20210214204524090

67开窗函数求最晚日期

/*开窗函数分组求最大时间,然后用子查询筛选*/
select n.un u_n, n.cn c_n,n.d 
from(
        select u.name un
                , c.name cn
                , l.date,
                (max(l.date) over(partition by l.user_id)) d
        from login l,user u,client c
        where l.user_id=u.id
        and c.id=l.client_id
    ) n
where n.date=n.d
order by u_n;

68求初始注册日留存率

  • 使用开窗函数
select
round(
        (
            select  
            count(*) -- 通过where找到第二天仍然登陆的用户记录数
            from
                (
                    select -- 1找到初始登陆日期
                    user_id
                    ,l.date
                    ,min(date) over(partition by user_id) as first_date
                    from login l
                ) as temp1
            where temp1.date = date_add(first_date,interval 1 day)
        )
    /
        (
            select -- 统计用户总数
            count(distinct user_id)
            from login
        )
    ,3)
as p 
  • 使用where子查询
SELECT
ROUND(
    COUNT(DISTINCT user_id)*1.0  
            /( -- 总用户量
            SELECT 
             COUNT(DISTINCT user_id) 
             FROM login
            )
    , 3)
FROM login
WHERE (user_id, date) -- 筛选出所有第二天登陆的用户
IN
(    -- 如果第二天登陆的日期和id
    SELECT user_id
    , DATE_ADD(MIN(date),INTERVAL 1 DAY) 
    FROM login GROUP BY user_id
);

date_add函数的使用:链接

DATE_ADD(start_date, INTERVAL expr unit)

常用unit
second,minute,hour,day,month,year

69使用row_number 来统计每天新注册人数

select 
date
,sum(
    case tem.rk
    when tem.rk = 1 then 1
    else 0
    end
) as new
from
(
    select
    user_id
    ,date
    ,row_number() over(partition by user_id order by `date`) as rk
    from login
) as tem
group by tem.date

70按日期统计留存率

select 
log_today.date
,round(count(distinct log_nextday.user_id)-- 当天新用户的数量
        /
        count(distinct log_today.user_id)-- 第二天重新登录的新用户数量
       ,3) as p
from login as log_today
left join(-- 注意要使用左连接
                select -- 1 将日期向前移动一天,从而进行表连接,判断第二天留存率
                user_id
                ,date_sub(date,interval 1 day) as date
                from login
            ) as log_nextday
    on log_today.date = log_nextday.date
    and log_today.user_id = log_nextday.user_id
where (log_today.user_id,log_today.date) -- 筛选每天登陆的新用户,就是这里把没有新用户登陆的天给筛选掉了,因此需要union
        in (
            select user_id
            ,min(date)
            from login
            group by user_id
        )
group by log_today.date
union -- 将没有新用户的登陆的天,补充留存率为零
select date 
,0.000 as p
from login
where date not in
    (
        select
        min(date)
            from login
            group by user_id
    )
order by date

71按日期和用户的累计和

select
u.name as u_n
,login.date
,ps_num
from 
    (
        select
        user_id
        ,date
        ,sum(number) over(partition by user_id order by date) as ps_num
        from passing_number
    ) as pas
    join login
        on login.user_id = pas.user_id
        and login.date = pas.date
    join `user` u 
    on u.id = login.user_id
order by date,u_n

72普通分组求平均

select
job
,round(avg(score),3) as avg_score
from
grade
group by job
order by avg_score desc

73大于平均值筛选

select
g1.*
from
grade g1
join (
    select
    id,
    avg(score) over(partition by job) avg_score
    from grade
) g2
on g1.id = g2.id
where g1.score > g2.avg_score
order by id

74求分组最高的两个值

select 
g.id
,l.name
,g.score
from grade g 
join `language` l
    on g.language_id = l.id
join (
    select
    id
    ,dense_rank() over(partition by language_id order by score desc) as rk
    from grade
) as tem
    on tem.id = g.id
where tem.rk in (1,2)
order by name asc,score desc

75求中位数的位置

select
job
,floor(( count(*) + 1 )/ 2 ) AS `start`
,floor(( count(*) + 2 )/ 2 ) AS 'end'
from grade
group by job
order by job
  • 取整函数
    • 四舍五入round()
    • 向上取整ceiling()
    • 向下取整floor()

76自连接求中位数

select
g1.id
,g1.job
,g1.score
,g2.rk as t_rank
from grade g1
join (
        select 
        id
        ,row_number() over(partition by job order by score desc) as rk-- 每条记录的排序
        ,count(id) over(partition by job rows between unbounded preceding and unbounded following) as num -- 每个job的记录数量
        from grade
    ) as g2
on g1.id = g2.id
where -- 判断中位数
    g2.rk = floor((g2.num + 1 )/ 2 )
    or g2.rk = floor((g2.num + 2 )/ 2 )
order by id

er_id
order by date,u_n


## 72普通分组求平均

```mysql
select
job
,round(avg(score),3) as avg_score
from
grade
group by job
order by avg_score desc

73大于平均值筛选

select
g1.*
from
grade g1
join (
    select
    id,
    avg(score) over(partition by job) avg_score
    from grade
) g2
on g1.id = g2.id
where g1.score > g2.avg_score
order by id

74求分组最高的两个值

select 
g.id
,l.name
,g.score
from grade g 
join `language` l
    on g.language_id = l.id
join (
    select
    id
    ,dense_rank() over(partition by language_id order by score desc) as rk
    from grade
) as tem
    on tem.id = g.id
where tem.rk in (1,2)
order by name asc,score desc

75求中位数的位置

select
job
,floor(( count(*) + 1 )/ 2 ) AS `start`
,floor(( count(*) + 2 )/ 2 ) AS 'end'
from grade
group by job
order by job
  • 取整函数
    • 四舍五入round()
    • 向上取整ceiling()
    • 向下取整floor()

76自连接求中位数

select
g1.id
,g1.job
,g1.score
,g2.rk as t_rank
from grade g1
join (
        select 
        id
        ,row_number() over(partition by job order by score desc) as rk-- 每条记录的排序
        ,count(id) over(partition by job rows between unbounded preceding and unbounded following) as num -- 每个job的记录数量
        from grade
    ) as g2
on g1.id = g2.id
where -- 判断中位数
    g2.rk = floor((g2.num + 1 )/ 2 )
    or g2.rk = floor((g2.num + 2 )/ 2 )
order by id
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

牛客网SQL题目解析(答案+解析+理解) 的相关文章

  • 如何在 phpmyadmin 中创建 MySQL 触发器

    我想在 MySQL 中创建一个触发器 我运行以下命令 mysql gt delimiter mysql gt CREATE TRIGGER before insert money BEFORE INSERT ON money gt FOR
  • 如何有效地从 DB2 表中删除所有行

    我有一个大约有 50 万行的表 我想删除所有行 如果我做简单的delete from tbl 事务日志已满 我不关心这种情况下的事务 无论如何我都不想回滚 我可以删除许多事务中的行 但是有更好的方法吗 如何有效地从 DB2 中的表中删除所有
  • Python:如何使用生成器来避免 sql 内存问题

    我有以下方法来访问 mysql 数据库 并且查询在服务器中执行 我无权更改有关增加内存的任何内容 我对生成器很陌生 并开始阅读更多有关它的内容 并认为我可以将其转换为使用生成器 def getUNames self globalUserQu
  • 查询中列的顺序重要吗?

    当从 MySQL 表中选择列时 与表中的顺序相比 选择列的顺序是否会影响性能 不考虑可能覆盖列的索引 例如 您有一个包含行 uid name bday 的表 并且有以下查询 SELECT uid name bday FROM table M
  • SPARK SQL - 当时的情况

    我是 SPARK SQL 的新手 SPARK SQL 中是否有相当于 CASE WHEN CONDITION THEN 0 ELSE 1 END 的内容 select case when 1 1 then 1 else 0 end from
  • 如何在Oracle中使用Timestamp_to_scn和Scn_to_timestamp?

    我的查询结果是这样的 select cast to date a start time mm dd yyyy hh mi ss pm as timestamp date of call ora rowscn from calling tab
  • 如何使用PostGIS将多边形数据转换为线段

    我在 PostgreSQL PostGIS 中有一个多边形数据表 现在我需要将此多边形数据转换为其相应的线段 谁能告诉我如何使用 PostGIS 查询进行转换 提前致谢 一般来说 将多边形转换为线可能并不简单 因为没有一对一的映射 http
  • 截断 Mysql 表 Cron 作业?

    我在如何使用 cron 作业截断 Mysql 表时遇到了一些麻烦 无论我尝试什么 我似乎都无法让数据库清除表格 感谢您的帮助 mysql uderp example pexample hlocalhost Dexample e TRUNCA
  • 阻止注销页面后的后退按钮

    我有 php 注销页面 当用户单击注销链接时 请参阅此页面并重定向到索引页面 但是当单击后退按钮时 我会看到带有用户数据的上一页 当然 当我刷新页面时 我看不到以前的页面和数据 我在单击注销并单击后退按钮后检查了其他代码 drupal 但我
  • MySQL Connector/C++ 库链接错误问题

    PROBLEM 好吧 我一直在尝试遵循 MySQL Forge Wiki 和其他一些网站上的示例代码 这些网站提供了有关如何获得简单数据库连接的教程 但由于某种原因 我的项目总是因链接错误而失败 我可以我自己不明白为什么或如何解决它 我仍在
  • 拆分列中的字符串并在列中添加值

    我有一个包含几行数据的表 如下所示 16 W 2 Work ALBO 00 Proposal ALxO Amendement 1 20091022 signed pdf 17 W 2 Work ALBO 00 Proposal Level1
  • MySQL 使用 ALTER IGNORE TABLE 出现重复错误

    我的 MySQL 中有一个有重复项的表 我尝试删除重复项并保留一项 我没有主键 我可以通过以下方式找到重复项 select user id server id count as NumDuplicates from user server
  • 为什么我的 if 语句没有按我预期的方式工作?

    我正在尝试实现以下目标 我向我的 SQL 数据库询问使用SELECT FROM subjects 这样做之后我要求使用数组mysqli fetch assoc 在那之前一切都很好 现在的问题是 当我尝试在每个循环中修改 genero 的值
  • 在sqlite SQL语句中与order by子句结合使用limit

    下面的两条 SQL 语句总是会产生相同的结果集吗 1 SELECT FROM MyTable where Status 0 order by StartTime asc limit 10 2 SELECT FROM SELECT FROM
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • sql server 按组排名

    问题看似简单 但我却无法理解 这是针对 sql 服务器的 what I have in a table What I need as a output cksum id cksum id 2162514679 204 2162514679
  • 忽略重复条目并在 EF Core 中的 DbContext.SaveChanges() 上提交成功条目

    我有一个 ASP Net Core 2 2 Web API 在我的一个控制器操作中 我向 MySQL 数据库表添加了一堆行 我使用的是 Pomelo 例如 dbContext AddRange entities dbContext Save
  • Mysql 创建定义器

    我创建了一个在 CentOS Web 服务器上运行的 Intranet Web 应用程序 该应用程序使用另一个本地服务器 始终是 CentOS 作为 MySQL 数据库 在数据库内部我创建了例程 这些例程总是这样开始 CREATE DEFI
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • MySQL 查询计算上个月

    我想计算上个月的订单总额 我收到了从当前日期获取当月数据的查询 SELECT SUM goods total AS Total Amount FROM orders WHERE order placed date gt date sub c

随机推荐

  • cross-env NODE_ENV=development作用

    cross env 作用 它是运行跨平台设置和使用环境变量的脚本 当我们使用 NODE ENV production 来设置环境变量的时候 大多数windows命令会提示将会阻塞或者异常 或者 windows不支持NODE ENV deve
  • Web Server市场占有率调查

    目录 一 理论 1 Web Server市场占有率调查 一 理论 1 Web Server市场占有率调查 1 netcraft 查询 每月netcraft公司都会出一次调查报告 netcraft官方 Netcraft Leader in P
  • 【开发技术经验分享精华版】计算机毕业设计吊打导师Spark+SpringBoot文档主题词自动提取分析与推荐系统 文本分类

    开发技术 前端 vue js 后端 springboot mybatis plus 数据库 mysql 算法 机器学习 深度学习 IK分析 lstm情感分析 文本分类 大数据分析 spark echarts hadoop 特色 创新点 文档
  • leetcode743. 网络延迟时间(中等, dijkstra)

    思路 单源最短路径 gt dijkstra 模板 class Solution public using PII pair
  • GOM 登录器源码及编译教程

    常见登录器引擎如下 BLUE LEGEDN引擎 一般应用于1 70 1 76 复古 80英雄合击 85英雄合击版本 MirXM2引擎 一般应用于1 70 1 76 复古 80英雄合击 85英雄合击版本 3km2引擎 一般应用于1 95 英雄
  • matlab 快速均匀采样

    目录 一 算法概述 二 代码实现 三 结果展示 四 测试数据 一 算法概述 实现从every k points个点中选取一个来达到下采样的目的 二 代码实现 清空变量 clc clear close all
  • java找不到符号解决办法

    一 java找不到符号 如果你的代码里没有报错 明明是存在的 但是java报错找不到符号 像下面这样子 二 解决步骤 1 清除编码工具缓存 本人用的idea eclipse清除缓存方式有需要的可以百度一下 2 如果是mavne项目的 先cl
  • valid 与 same的卷积方式

    http www jianshu com p 05c4f1621c7e 这个简书的作者已经写得很清楚了
  • spss 异常值

    spss 异常值剔除 用什么方法 1 可以通过 分析 下 描述统计 下 频率 的 绘制 直方图 看图发现频数出现最少的值 就可能是异常值 但还要看距离其它情况的程度 2 可通过 分析 下的 描述统计 下的 探索 下的 绘制 选项的 叶茎图
  • 嵌入式AI-K210篇-硬件-模型训练、部署

    K210的其他参数如下 双核 64 bit RISC V RV64IMAFDC RV64GC CPU 400MHz 可超频到600MHz 双精度 FPU 8MiB 64bit 片上 SRAM 6MiB通用SRAM 2MiB的AI专用SRAM
  • 谷歌机器学习:问题构建 (Framing):机器学习主要术语

    谷歌机器学习 问题构建 Framing 机器学习主要术语 地址 https developers google cn machine learning crash course framing ml terminology 什么是 监督式
  • Linux只允许特定IP访问特定端口

    目录 1 查看 开启 关闭防火墙 2 查看 开放 关闭端口 3 给指定的IP开放 关闭指定的端口 4 规则的持久化位置 5 其它命令 1 查看 开启 关闭防火墙 查看服务器的防火墙状态可使用如下命令 查看防火墙状态 systemctl st
  • sqlserver单独备份某个表_T+应急备份和恢复数据方法汇总

    对于企业系统管理员来讲 定时地将企业数据备份出来存储到不同的介质上 如常见的光盘 网络磁盘等等 对数据的安全性是非常重要的 如果企业由于不可预知的原因 如地震 火灾 计算机病毒 人为的误操作等等 造成数据损失或丢失 需要对数据进行恢复 此时
  • 快速搭建你的MQTT服务器

    MQTT服务器在Linux和Windows上的搭建稍微有些区别 不过使用第三方开源的项目一般会有比较详细的说明文档 不做过多赘述 笔者搭建环境是windows10 ActiveMQ 1 windows MQTT服务器下载 https act
  • neo4j修改节点(包括属性,关系)

    将 傅式级数 这个节点删除 并把 单位冲激序列的傅里叶变换 这个节点 指向 傅氏级数 这个节点 match r where id r 76247 detach delete r match p KnowledgeBlock name 单位冲
  • Sass 条件-循环语句

    学习Sass中 if else for while each 一 条件判断 if else 示例 1 mixin blockOrHidden boolean true 2 if boolean 3 debug boolean is bool
  • OpenCV机器视觉-边缘与轮廓

    边缘与轮廓 基于图像边缘提取或二值化的基础寻找对象轮廓 边缘提取的阈值会最终影响轮廓发现的结果 主要API要有以下俩个 findContours发现轮廓 drawContours绘制轮廓 查找轮廓 处理的图像 轮廓列表 继承关系 cv fi
  • druid的解密

    项目中往往配置的数据库密码不是明文 当我们的数据库配置的密码是一系列的你看不懂的文字时 你就应该考虑是不是是druid的加解密了 使用druiid的加解密 首先应该配置依赖
  • 简易虚拟培训系统-UI控件的应用3

    目录 Button组件的组成 Button组件方法1 在Button组件中设置OnClick 回调 Button组件方法2 在脚本中添加Button类的监听 上一篇使用了文件流读取硬盘数据并显示在Text组件中 本篇增加使用按钮来控制显示哪
  • 牛客网SQL题目解析(答案+解析+理解)

    本文记录了牛客网sql全部题目的答案与难题解析 部分题目包含多种解法 并且涵盖了开窗函数等各种语法点的理解 标题中高亮的题目 是易错题 牛客网刷题链接 牛客网sql在线练习 本文所有语句使用mysql8 0 参考教程资源 mysql教程1