Java面试题【2】

Java面试题——编程题部分

1.见题目

  1. count文件用程序读取,并打印在控制台上
  2. count内的每个编码出现的次数统计出来
    • 有多少个
    • 每个出现的次数
  3. 将结果通过textexcel输出到文件
B7151890053952,B7151890053952,B7151890053952,B715189005391880590647,39101880612299,39101880612299,39101880612299,39621353,39101880621353,39101880621353,39101880621353,39101835,B7151890054335,39101880621376,39101880621439,B7151890057151890054598,39101880613720,39101880590256,3910188062105880621288,39101880621058,39101880621117,39101880621388,39121388,39101880621058,B7151890054697,39101880621117,39101889,39101880621388,39101880621058,B7151890054697,39101880621101880590102,39101880590102,39101880590102,B7151890053952
public class Demo01{
    public static void main(String[] args) throws IOException{
        //1.将count文件用程序读取,并打印在控制台上
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("count源文件.txt")));
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
        }
        br.close();
        //2.将count内的每个编码出现的次数统计出来  有多少个  每个出现的次数 并将结果写入文件
        /*
        	思路:对文件按照单个字符进行读取,判断读取到的字符是否为 "," 若不是,将其存入StringBuilder,若是将StringBuilder中的内容转换成字符串,即为编码,将编码存入map集合,存的时候判断该编码是否已经存在,若存在,让其该编码的次数进行 +1,若不存在,将该编码存入map,次数设为1
        */

        PrintWriter pw = new PrintWriter(new FileOutputStream("result.txt"),true);
        Map<String,Integer> map = new HashMap()<>;
        StringBuilder sb = new StringBuilder();
        //按照单个字符读取数据
        InputStreamReader isr = new InputStreamReader(new FileInputStream("count源文件.txt"));
        int ch = -1;
        while((ch = isr.read()) != -1){
            //判断字符是否为 ,
            if(ch != ','){
                sb.append((char)ch);
            }else{
                String code = sb.toString();
                //判断 code 是否存在于 map中
                if(map.containsKey(code)){
                    map.put(code,map.get(code) + 1);
                }else{
                    map.put(code,1);
                }
                //清空 StringBuilder
                sb.delete(0,sb.length());	//包头不包尾
            }
        }
        String count = "编码的个数为:" +  map.size();	
        System.out.println(count);
        pw.println(count);

        map.forEach((k,v)->{
            String line = "编码:" + k + "出现的次数:" + v;
            System.out.println(line);
            pw.println(line);
        });

        isr.close();
        pw.close();
    }
}

关于IO流:

  • 按照流向分:输入流、输出流
  • 按照读写单位分:字节流、字符流
  • 低级流和高级流:低级流直接面向文件操作,高级流直接面向流

字节流:若操作文件为非文本文件(图片、音频、视频),此时必须选择字节流进行读写

  • 抽象基类:(都是抽象类,不能实例化,只能创建子类对象)

    • InputStream
    • OutputStream
  • 文件流:(输入流是读数据,输出流是写数据,参照物不同以内存为标准,从内存输出到文件是写,从文件输入到内存是读)

    • FileInputStream

      • 构造方法:

        FileInputStream(File file){}	//通过打开一个到实际文件的连接来创建一个FieInputStream,该文件通过文件系统中的File对象file指定。
        FileInputStream(String name){}	//通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径名name指定。
        
      • 读数据:

        read():int	//从此输入流中读取一个数据字节,int表示读取到的字节
        read(byte[]):int	//从目标文件读取字节数组个长度的数据字节
        /*
        关于字符占用的字节:
        	如果不涉及任何编码字符集,此时一个字符(中文/英文、数字) 占用2个字节   
             如果文件的字符集为utf-8,一个英文、数字占用1个字节,一个中文占用3个字节   
             如果文件的字符集GBK,一个英文、数字占用1个字节,一个中文占用2个字节   
         */  
        
        public static void main(String[] args) throws IOException{
            FileInputStream fis = new FileInputStream("a.txt");
           	// int b = -1;
            //while((b = fis.read()) != -1){	//单个字节读
        
            byte[] bys = new byte[1024];
            int len = -1;
            while((len = fis.read(bys)) != -1){	//数组个字节读
                //System.out.println((char)b);
                System.out.println(new String(bys,0,len));
            }
            fis.close();
        }
        
    • FileOutputStream

      • 构造方法:

        FileOutputStream(File file){}	//创建一个向指定File对象表示的文件中写入数据的文件输出流。
        FileOutputStream(String name){}	//创建一个向具有指定名称name的文件中写入数据的文件输出流。
        FileOutputStream((File file/String name,boolean append){}	//若第二个参数值为true,则下次写为追加写入,为false和只写一个参数用法相同
        
      • 写数据:

        write(int):	//一次写一个字节,无返回值,失败则抛异常
        write(byte[]):	//一次写一个字节数组
        write(byte[],offset,len):	//一次将字节数组中实际有的内容写入文件
        
        public static void main(String[] args) throws IOException{
            FileInputStream fis = new FileInputStream("ArrayTest.java");
            FileOutputStream fos = new FileOutputStream("copy.java");
        
            //按照单个字节进行复制
            /*int by = -1;
            while((by=fis.read())!=-1){
                fos.write(by);
            }
            */
        
            //按照字节数组复制
            byte[] bys = new byte[20];
            int len = -1;	//实际读取长度
            while((len = fis.read(bys)) != -1){	//数组个字节读
                fos.write(bys,0,len));
            }
            fos.close();
            fis.close();
        }
        
  • 字节缓冲流:(在文件流的基础上多了缓冲区,提高读写效率)

    • BufferedInputStream

      • 构造方法:

        BufferedInputStream(InputStream){}	//创建一个BufferedInputStream并保存其参数,即输出流in,以便将来使用
        
      • 读数据:

        read():int	//从此输入流中读取一个数据字节,int表示读取到的字节
        read(byte[]):int	//从目标文件读取字节数组个长度的数据字节
        
    • BufferedOutputStream

      • 构造方法:

        BufferedOutputStream(InputStream){}	
        
      • 写数据:

        write(int):	//一次写一个字节,无返回值,失败则抛异常
        write(byte[]):	//一次写一个字节数组
        write(byte[],offset,len):	//一次将字节数组中实际有的内容写入文件
        

字符流:操作单位是字符,会避免乱码的产生,且读写效率比字节流高,但字符流使用前提是操作的必须是文本文件

  • 抽象基类:(都是抽象类,不能实例化,只能创建子类对象)

    • Reader
    • Writer
  • 转换流:

    • InputStreamReader

      • 构造方法:

        InputStreamReader(InputStream in){}	//创建一个使用默认字符集的InputStreamReader
        InputStreamReader(InputStream in,String charsetName){}	//创建一个使用指定字符集的InputStreamReader
        
        /*
        编码: 字符 --> 字节
        解码: 字节 --> 字符
        */
        
      • 读数据:

        read():int	//一次读取一个字符
        read(char[]):int	//一次读取一个字符数组个字符,返回值表示实际读取的长度
        
        public static void main(String[] args) throws IOException{
            InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
        
            //按照单个字符读取a.txt中字符并输出
            /*int ch = -1;
            while((ch=isr.read())!=-1){
                System.out.println((char) ch);
            }
            */
        
            //按照字符数组读取数据
            char[] chs = new char[3];
            int len = -1;	//实际读取长度
            while((len = isr.read(chs)) != -1){	//数组个字节读
                System.out.println(Arrays.toString(chs));
                System.out.println(new String(chs,0,len));
            }
            isr.close();
        }
        
    • OutputStreamWriter

      • 构造方法:

        OutputStreamWriter(OutputStream out){}	//创建一个使用默认字符集的OutputStreamWriter
        OutputStreamWriter(OutputStream out,String charsetName){}	//创建一个使用指定字符集的OutputStreamWriter
        
      • 写数据:

        write(int):	//一次写一个字符
        write(char[],off,len):	//写入字符数组的某一部分  高频
        write(String,off,len):	//写入字符串的某一部分
        
        public static void main(String[] args) throws IOException{
            InputStreamReader isr = new InputStreamReader(new FileInputStream("ArrayTest.java"));
            OutputStreamWriter osr = new OutputStreamWriter(new FileOutputStream("wcopy.java"));
        
            //按照单个字符复制
            /*int ch = -1;
            while((ch=isr.read())!=-1){
                osw.write(ch);
            }
            */
        
            //按照字符数组复制
            char[] chs = new char[3];
            int len = -1;	//实际读取长度
            while((len = isr.read(chs)) != -1){	//数组个字节读
                osw.write(chs,0,len);
            }
            isr.close();
            osw.close();
        }
        
  • 字符缓冲流:(按行读写数据)

    • BufferedReader

      • 构造方法:

        BufferedReader(Reader in){}	//创建一个使用默认大小输入缓冲区的缓冲字符输入流
        BufferedReader(Reader in,int size){}	//创建一个使用指定大小输入缓冲区的缓冲字符输入流
        
      • 读数据:

        readLine():String	//读取到回车换行就结束,但不会读取回车换行,若读到末尾则返回null
        
        public static void main(String[] args) throws IOException{
            //使用字符缓冲流复制文件
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("Demo01.java")));
            PrintWriter pw = new PrintWriter(new FileOutputStream("brcopy.java"),true);
        
            //复制
            String line = null;
            while((line = br.readLine())!= null){
                pw.println(line);
            }
        	pw.close();
            br.close();
        }
        
    • BufferedWriterPrintWriter 具有自动行刷新功能,默认关闭

      • 构造方法:

        PrintWriter(File file/String name){}	//创建指定文件创建不具有自动刷新的新的PrintWriter
        PrintWriter(File file String csn){}	//创建具有指定文件和字符集且不具有自动刷新的新的PrintWriter
        PrintWriter(OutputStream out,boolean autoFlush){}	//通过现有的OutputStream创建新的PrintWriter,且带有自动刷新
        PrintWriter(Writer out,boolean autoFlush){}	//通过现有的Writer创建新的PrintWriter,且带有自动刷新
        
      • 写数据:

        println(String):	//自动行刷新
        print(String):	//自动行刷新不启动 
        

字节流和字符流的选择:

  • 字节流:
    1. 操作的文件是非文本文件
    2. 需求中分析得出必须按照字节进行读写,此时选择字节流
  • 字符流:
    1. 操作的文件是文本文件

对象流:对对象数据进行读写,对象读写必须序列化

/*
序列化接口: Serializable  叫做标志接口
序列化: 对象数据 --> 字节数据
反序列化: 字节数据 --> 对象数据

反序列化过程: 将文件中读取到的序列版本号与.class文件中的序列版本号进行对比,若相等,则反序列化成功,若不相等,则反序列化失败

序列化版本号: 若实体类中没有序列版本号,则编译时Java为其随机生成版本号,每次编译均重新生成,若实体类中有序列版本号,则后期文件不论如何编译,版本号均不发生改变

idea中设置序列版本号提示步骤:
File-->Settings-->Editor-->Inspections-->java-->serialization issues-->勾选 serializab1e without serialversionUID
*/

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SlqzCR0r-1688007826400)(../../../AppData/Roaming/Typora/typora-user-images/image-20230628135924786.png)]

  • ObjectInputSteam

    • 构造方法:

      ObjectInputSteam(InputSteam)	//创建从InputSteam读取的ObjectInputSteam
      
    • 读对象数据

      readObject():Object
      
  • ObjectOutputSteam

    • 构造方法:

      ObjectOutputSteam(OutputSteam)	//创建写入指定的OutputSteam的ObjectOutputSteam
      
    • 写对象数据

      writeObject(Object)
      

2.本地有一个存放学生的a.txt文件,内容如下

学号  姓名  性别  年龄  联系电话
11 ,   张三, 男 , 23 , 18523214679
12 ,   杨丽, 女 , 23 , 15678776678
13 ,   小明, 男 , 30 , 13345433451
14 ,   小月, 男 , 19 , 18789775567
  1. 读取txt文件的所有内容并显示
  2. 输出所有性别为男的数据
  3. 对读取到的数据按年龄从大到小输出(忽略第一行)
  4. 将第三步排序后的数据输出到文件result.txt文件中
public class Demo01{
    public static void main(String[] args) throws IOException{
        //1.读取txt文件的所有内容并显示
        //2.输出所有性别为男的数据
        //3.对读取到的数据按年龄从大到小输出(忽略第一行)
        BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));

        //3中排序使用 TreeMap
        Map<Integer,String> map = new TreeMap<>();  
        br.readLine();	//忽略第一行
        String line = null;
        while((line = br.readLine()) != null){
            System.out.println(line);
            //输出性别为男的数据
            String gender = line.split(",")[2].trim();
            if("男".equals(gender)){	//equals比较将固定值放在前面
                System.out.println(line); 
            }

            //将数据按照年龄降序输出
            String ageStr = line.split(",")[3].trim();
            int age = Integer.parseInt(ageStr);
            map.put(age,line);
        }

        //将map转换为list,根据value年龄进行降序排列(自定义排序)
        List<Map.Entry<String,Integer>> list = new ArrayList<>(map.entrySet());
        list.sort((o1,o2)->o2.getValue().compareTo(o1.getValue));

        //4.将第三步排序后的数据输出到文件result.txt文件中
        PrintWriter pw = new PrintWriter(new FileOutputStream("result.txt"),true);
        pw.println(title);
        list.forEach(entry->{
            String stu = entry.getKey();
            System.out.println(stu);
            pw.println(stu);

        });
        pw.close();
        br.close();
    }
}

3.请写出对map集合的遍历实现(尽可能写出多种方式)

  • for循环

    Map<String,Integer> map = new HashMap<>();
    for(Map.Entry<String,Integer> entry:map.entrySet()){
        System.out.println(entry.getKey() + "-" + entry.getValue());
    }
    
  • lambda表达式

    Map<String,Integer> map = new HashMap<>();
    map.forEach((k,v)-> System.out.println(k + "-" + v));
    
  • 迭代器

    Map<String,Integer> map = new HashMap<>();
    Iterator<Map.Entry<String,Integer>> it = map.entrySet().iterator();
    while(it.hasNext()){
        Map.Entry<String,Integer> entry = it.next();
        System.out.println(entry.getKey() + "-" + entry.getValue());
    }
    

4.在Java中如何获得当前时间,如何转换为某字符串格式

LocalDateTime.now();  //格式需要转换 获取当前日期时间
LocalDate.now();  //格式需要转换 获取当前日期,没有时间
new Date();		//格式需要转换

//日期转换类:    DateTimeFormatter.ofPattern("");


public static void main(String[] args){

    //新日期
    //Java8中获取当前日期
    LocalDateTime time = LocalDateTime.now();
    System.out.println(time);,
    //将日期类型转换为某种字符串格式
    DateTimeFormatter dtf =
        DateTimeFormatter.ofPattern( "yyyy-MM-dd HH : mm : ss" );
    String dateStr = dtf.format(time);
    System.out.println(dateStr);


    //将String类型转换成日期 字符串必须满足Java所识别的日期
    String str = "2023-12-12 12:12:12";
    LocalDateTime time =  LocalDateTime.parse(str,dtf);
    System.out.println(time);


    //旧日期 Date --> String
    Date date = new Date();
    SimpleDateFormat sdf =
        new SimpleDateFormat("yyyy/MM/dd HH : mm : ss");
    String dateStr2 = sdf.format(date);
    System.out.println(dateStr2);

    //旧日期 String --> Date
    String str = "2023/11/11 11:11:11";
    try{
        Date cur = sdf.parse(str);
        System.out.println(cur);
    }catch(ParseException e){
        e.printStackTrace();
    }
}

5.对数组进行去重

int[] ary = {1,2,1,1,1,2,3,4,623,62,2,4,1,0,0};

List<Integer> list = new ArrayList<>();
for(int i:ary){
    if(!list,contains(i)){
        list.add(i);
    }
}
/*
int[] dest = new int[list.size()];
for(int i=0;i<list.size();i++){
    dest[i] = list.get(i);
}
*/
Integer[] dest = list.toArray(new Integer[list.size()]);
System.out.println(Arrays.toString(dest));

6.对集合进行去重

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(1);
list.add(4);
list.add(5);
list.add(7);
list.add(1);
list.add(3);
list.add(4);
list.add(5);

List<Integer> list1 = new ArrayList<>();
/*
//以下遍历会产生并发异常 java.util.ConcurrentModificationException
for(Integer i : list){
    if(!list1.contains(i)){
        list1.add(i);
    }else{
        list.remove(i);
    }
}
*/

//使用迭代器
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
    //取出元素
    Integer i = it.next();
	if(list1.contains(i)){
        it.remove();
    }else{
        list1.add(i);
    }
}

System.out.println("去重后的结果为:");
list.forEach(i->System.out.print(i + " "));

7.请写出懒汉式和饿汉式单例模式

//懒汉式
public class SingleTon{
    private SingleTon(){}
    private static SingleTon singleTon;
    public static synchronized SingleTon getInstance(){
        if(singleTon == null){
            singleTon = new SingleTon();
        }
        return singleTon;
    }
}


//饿汉式
public class SingleTon{
    private SingleTon(){}
    private static SingleTon singleTon = new SingleTon();
    public static SingleTon getInstance(){
        return singleTon;
    }
}


//饿汉式为什么不加 synchronized,饿汉式是如何保证线程安全的
//对象在类加载时期已经被创建完成,运行期不再创建,多个线程并发访问的是同一个SingleTon

8.写一段代码删除list中所有结尾数字可被2整除的节点

List<String> list = new ArrayList<>();
list.add("aaabbbccc1");
list.add("aaabbbccc2");
list.add("aaabbbccc3");
list.add("aaabbbccc4");
list.add("aaabbbccc5");
list.add("aaabbbccc6");
list.add("aaabbbccc7");
list.add("aaabbbccc8");
//在遍历过程中删除元素,使用迭代器删除
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
    String ele = it.next();
    //截取数组
    int num = Integer.parseInt(ele.substring(9));
    if(num%2==0){
        it.remove();
    }
}
list.forEach(str->System.out.println(str));

9.如何对List根据age进行排序

Collections.sort(list, new Comparator<E>(){
    int compare(E o1,E o2){
        return o1.getAge().compareTo(o2.getAge());
    }    
});


list.sort(new Comparator<E>(){
    int compare(E o1,E o2){
        return o1.getAge().compareTo(o2.getAge());
    }    
});

10.从表t1(有字段idnamesexscore)中取出sex为男,score列前十名的name字段

select name from t1 where sex = '男' order by score desc limit 0,10;

limit用法:

  • limit m, n
    • m表示查询数据的起始下标,n表示查询数量
  • limit n:从起始位置开始的n条数据

11.基于表user,查出表中第10条到第20条连续分页数据的sql语句

select * from user limit 9,11

12.请描述查询语句中各部分的执行顺序

select distinct ... from A join B on a.xx=b.xx where xx=? and xx=? group by xx having xx=? order by ... limit m, n
  1. from:产生虚拟表v1 产生的是笛卡尔积
  2. on:根据连接条件进行筛选,基于v1,产生虚拟表v2
  3. left/right join: 若是外连接,将主表中的所有数据进行补充到v2表中
  4. where:根据查询条件,从v2中进行数据筛选,产生虚拟表v3
  5. group by:对v3分组,产生虚拟表v4
  6. having:对分组后的结果再次筛选,产生虚拟表v5
    • having 是分组后结果进行筛选,没有分组进行筛选使用的是`where``
  7. select:选择最终要显示的字段,产生虚拟表v6
  8. distinct:对结果集进行去重,产生虚拟表v7
  9. order by:对结果根据某字段进行升序 / 降序排列

13.表名:stu_score,获取班级的最后一名

idnamescorebj
1张三821班
2李四641班
3王五982班
4赵六761班
5白七1002班
-- 1.求出每个班级的最低分
-- 2.拿刚才的结果表与原表联查,条件为班级号相等同时分数相等,即可以查到每个班的最低分对应的人

select ss.* from stu_score ss join
(select bj,MIN(score) min from stu_score group by bj) tmp
on ss.bj = tmp.bj and ss.score = tmp.min

14.表user,字段有id(非自增,不连续),age,name,sex,addTime。求创建时间(addTime)在2023-05-222023-06-12之间的所有数据

-- 数据库中的边界值都包括
select * from user where addTime between '2023-05-22' and '2023-06-12';	

select * from user where addTime >= '2023-05-22' and addTime <= '2023-06-12';	

15.向user表中添加一条数据,包括创建时间

insert into user values(10,21,'tom','男','2023-06-30')

16.有以下表写出sql

student表

snosnamesage
1张三12
2李四14
3王五15
4赵六18

course表

cnocname
1语文
2数学
3王五

score表

snocnoscore
1180
1298
2192
  • 查询所有学生学号、姓名、选课数、总成绩

    -- 学生表和成绩表外连接查询,连接条件学号相等
    -- 根据学生表的学号进行分组,统计每个学生的总成绩和选课数
    
    SELECT s.sno,sname,COUNT(con),SUM(score) FROM student s LEFT JOIN
    score sc ON s.sno = sc.sno
    GROUP BY s.sno
    
  • 查询没有学完所有课程的学生学号、姓名

    -- 获取总课程数  select count(*) from course
    -- 查询成绩表中的课程数小于总课程数,查询每个学生的选课数,筛选选课数 < 总课数
    
    SELECT s.sno,sname FROM student s LEFT JOIN score sc ON s.sno = sc.sno
    GROUP BY s.sno HAVING COUNT(cno) < (select count(*) from course)
    

17.有以下表写出sql

student表

idstu_nostu_namestu_genderclass_id
12023001张三1
22023002李四1
32023003王五2
42023004赵六3
52023005白七3

class表

idclass_name
1一班
2二班
3三班

score表

stu_idchinesemath
17080
28298
39192
48090

业务场景限制:一个班有多名学生,一名学生只属于一个班级,学生有可能没有成绩

  • 查询所有学生的信息(学号、姓名、性别、班级名称)

    select stu_no,stu_name,stu_gender,class_name from student s join class  c on s.class_id = c.id
    
  • 查询所有人(包括没有成绩的学生)的课程分数(学号、姓名、性别、班级名称、语文分数、数学分数)

    select stu_no,stu_name,stu_gender,class_name,chinese,math from student s
    join class  c on s.class_id = c.id left join score sc on sc.stu_id = s.id
    
  • 查询语文分数比“张三”高的学生(学号、姓名、性别、班级名称、语文分数)

    select stu_no,stu_name,stu_gender,class_name,chinese from student s
    join class  c on join score sc on sc.stu_id = s.id and s.class_id = c.id 
    where chinese >(select chinese from student s join score sc on s.id = sc.stu_id where stu_name = '张三')
    
  • 查询各科都合格(分数>= 60)的学生(学号、姓名、语文分数、数学分数)

    select stu_no,stu_name,chinese,math from student s join score sc on s.id = sc.stu_id where chinese >= 60 and math >= 60
    
  • 查询班级人数 >= 2的班级(班级编号、班级名称、人数)

    select s.class_id,class_name,count(stu_no) cou from student s join class c on s.class_id = c.id group by s.class_id having cou >= 2
    

count() 聚合函数的使用:

  • count(*):统计行
  • count(col):对这列中的数据进行计数

18.有以下表写出sql

score表

namecoursescore
张三语文81
张三数学79
李四数学93
王五语文92
王五数学88

查询每门课程都大于等于80分的学生信息

-- 求出每个学生的最低分,筛选最低分 >= 80 的学生
select name from score group by name having min(score) >= 80

19.有以下表写出sql

student(sno,sname,sage,ssex) 学生表
course(cno,cname,tno) 课程表
sc(sno,cno,score) 成绩表
teacher(tno,tname) 教师表
  • 查询课程1的成绩比课程2的成绩高的所有学生的信息

    select s.*,sc1.score '课程1',sc2.score '课程2' from sc sc1 join sc sc2 join student s on sc1.sno = sc2.sno and sc1.score > sc2.score and sc1.sno = s.sno where sc1.cno = 1 and sc2.cno = 2
    
  • 查询平均成绩大于60分的同学的学号和平均成绩

    select sno,avg(score) av from score group by sno having av > 60
    
  • 查询学过“李四”老师所教课程的所有同学的学号和姓名

    select distinct s.sno,sname from teacher t join course c join sc join student s on t.tno = c.tno and c.cno = sc.cno and sc.sno = s.sno where tname = '李四'
    
  • 查询姓“李”的老师的个数

    select count(*) from teacher where tname like '李%' 
    
  • 查询每门课程的选修人数(课程名称,学生数量)存在没有人选的课程

    select cname,count(sno) from course c left join sc on c.cno = sc.cno group by c.cno
    
  • 删除“1002”同学的“1”课程的成绩

    delete from sc where sno = 1002 and cno = 1
    
  • 修改tom的年龄为25

    update student set sage = 25 where sname = 'tom'
    
  • 查询选修人数最多的课程(课程id,课程名称,学生数量)考虑有多门课程都是选修最多的情况

    -- 查询选修人数最多的数目 思路:统计每门课程的选修人数,对人数进行降序排序,筛选第一条数据即为最多的选修人数
    select count(sno) cou from sc group by cno order by cou desc limit 1;
    -- 查询每门课程的选修人数,筛选人数=上述人数的课程
    select sc.cno,cname,count(sno) cou from course c join sc on sc.cno = c.cno group by sc.cno having cou = (select count(sno) cou from sc group by cno order by cou desc limit 1)
    

20.有以下表写出sql

成绩表 student_score

字段名称字段解释字段类型字段长度
student_id学号字符8
student_name姓名字符50
student_gander性别字符(男/女)4
course_id课程号字符5
score分数数值3
is_makeup当前考试是否为补考字符(补考:1,非补考:0)2

课程表 course

字段名称字段解释字段类型字段长度约束
course_id课程号字符5PK
course_name课程名字符30Not null
course_desc课程介绍字符60
  • 查询第一次考试后所有需要补考(小于60分)的学生姓名和这门课的名称和成绩

    select student_name,course_name,score from student_score ss join course c on c.course_id = ss.course_id where score < 60 and is_makeup = 0
    
  • 查询每个学生第一次考试后需要补考(小于60分)的课程平均分和科目数

    -- 筛选第一次考试的成绩不及格数据
    -- 针对以上数据,统计每个学生不及格科目数和课程平均分
    select student_id,student_name,count(course_id),avg(score) from student_score where is_makeup = 0 and score < 60 group by student_id
    
  • 查询所有参加补考的学生姓名、课程名称、补考成绩和非补考成绩

    -- 使用表的自连接查询,从一张成绩表中查询参加了补考的学生信息及补考成绩,到另一个成绩表中查询is_makeup = 0的数据,学号、课程编号均于另一张成绩表中相同的成绩数据
    
    select student_name,course_name,sc1.score,sc2.score from student_score sc1 join student_score sc2 join course c on c.course_id = sc1.course_id and sc1.student_id = sc2.student_id and sc1.course_id = sc2.course_id where sc1.is_makeup = 1 and sc2.is_makeup = 0
    

21.有以下表写出sql

员工(emp)包含字段编号(emp_no),姓名(emp_name),性别(emp_sex),部门编号(dep_no),部门表(dept)包含字段部门编号(dep_no),部门名称(dep_name),业绩表(salary),包含月份(month),员工编号(emp_no),业绩(salary)

  • 获取每个月每个部门的总业绩

    select month,d.dept_no,dep_name,sum(salary) from emp join dept join salary on emp.emp_no = salary.emp_no and emp.dep_no = dept.dep_no group by month,dept_no
    
  • 获取每个月每个部门的平均业绩

    select month,d.dept_no,dep_name,avg(salary) from emp join dept join salary on emp.emp_no = salary.emp_no and emp.dep_no = dept.dep_no group by month,dept_no
    

22.按照右侧的结果写出生成右侧结果的sql

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5f5ifu5-1688194979989)(../../../AppData/Roaming/Typora/typora-user-images/image-20230630225705208.png)]

-- 先从记录表中根据日期分组,统计出有那些日期
-- 根据分组后的日期到记录表中查询某天胜的场次
-- 根据分组后的日期到记录表中查询某天负的场次 

select match_date,
(select count(*) from match_record mr1 where mr1.match_date = mr.match_date and mr1.result = '胜') '胜',
(select count(*) from match_record mr2 where mr2.match_date = mr.match_date and mr2.result = '负') '负'
from match_record mr group by match_date

23.有以下表写出sql

用户表 user

字段名称字段解释字段类型说明
id编号varchar主键
name姓名varchar
sex性别varchar男女
age年龄int
birthday出生日期dateyyyy-MM-dd
state状态int1.在职 2.离职

角色表 role

字段名称字段解释字段类型说明
id编号varchar主键
name名称varchar
parentId性别varchar父角色id,根角色null
remark年龄varchar

用户角色关联表 user_role

字段名称字段解释字段类型说明
user_id学号varchar联合主键
role_id姓名varchar联合主键
  • 用户表中添加一条数据,请写出SQL语句

    insert into user values(1,'tom','男',21,'2023-12-14',1)
    
  • 在用户表中把姓名为"李四"的在职用户的年龄修改为28

    update user set age = 28 where name = '李四' and state = 1
    
  • 查询所有的角色名称为"技术人员",性别是女的在职人员

    select u.* from role r join user_role ur join user u on r.id = ur.role_id and ur.user_id = u.id where sex = '女' and state = 1 and r.name = '技术人员' 
    
  • 把角色名称为"研发人员"的用户"张三"从用户表中删除

    delete from user where id in (select u.id from role r join user_role ur join user u on r.id = ur.role_id and ur.user_id = u.id where u.name = '张三' and r.name = '研发人员') 
    
  • 查询年龄在18到24岁之间的男性在职人员

    select * from user where age between 18 and 24 and sex = '男' and state = 1
    
  • 查询年龄为18,19,20的男性和女性员工的人数,结果如下图所示:

    年龄
    1853
    1946
    2010
    select u.age 
    (select count(*) from user u1 where u1.age = u.age and u1.sex = '男') '男',
    (select count(*) from user u2 where u2.age = u.age and u2.sex = '女') '女',
    from user u where age between 18 and 20 group by age
    
  • 查询前50名姓“张”男员工

    select * from user where name like '张%' and sex = '男' limit 50
    
  • 查询所有根角色员工,根角色就是父角色为null的角色

    select u.* from role r join user_role ur join user u on r.id = ur.role_id and ur.user_id = u.id where r.parent_id is null
    

24.有以下表写出sql

有一张student,包括字段id和name,写出sql,将表中name字段中重复的记录删除,只保留重复数据中id最大的那一条数据

idname
1张三
2张三
3李四
4王五
5王五
delete from student where id not in (select max(id) from student group by name)

25.有以下guest表写出sql

账号消费时间金额班次
accountsdetailsdatemoneyclass
s001房费2023-04-01280001
s001酒水2023-06-15120001
s001房费2023-08-27300003
s002房费2023-04-0250
s003酒水2023-07-25180002
s004房费2023-03-21230
s005房费2023-04-19280001
s005酒水2023-06-28120
  • 查询出房费都大于200的账号

    -- 筛选出所有的房费数据
    -- 对以上数据根据账号进行分组,统计每个账号的房费最低消费金额
    -- 对以上数据进行再次筛选,筛选最低房费金额 > 200 的账号
    
    select accounts from guest where detail = '房费' group by accounts having min(money) > 200 
    
  • 查询出4月份每个账号酒水和房费的总金额

    -- 筛选出4月份的数据
    -- 对以上数据根据账号进行分组,统计每个账号4月份中消费的总金额
    
    select accounts,sum(money) from guest where date between '2023-04-01' and '2023-04-30' group by accounts
    
    select accounts,sum(money) from guest where month(date) = 1 group by accounts
    
    /*
    使用mysql提供的日期函数
    year(col) --获取该列中日期的年份的值
    month(col) --获取该列中日期的月份的值
    day(col) --获取该列中日期的天数
    date(col) --获取日期中的年月日
    hour(col) --获取小时
    minute(col) --获取分钟
    second(co1) --获取秒数
    */
    
  • 将不是房费的班次都改为‘001’

    update guest set class= '001' where details != '房费' 
    
  • 查询出消费都大于100的账号

    -- 选择每个账号最低消费金额大于100的
    -- 先查询每个账号的最低消费金额,然后筛选最低消费金额大于100
    
    select accounts from guest group by accounts having min(money) > 100
    

26.有以下表写出sql

员工表(emp)包含字段员工编号(empno),姓名(ename),工作岗位(job),上级领导编号(mgr),雇佣日期(hiredate),薪资(sal),佣金(comm),部门编号(deptno)

部门表(dept)包含字段部门编号(deptno),部门名称(dname),地点(loc)

  • 列出在每个部门工作的员工数量,平均工资

    -- 列出部门表和员工表进行外连接查询,部门表为主表
    -- 根据部门表的dept_no 分组,统计员工数据(对empno使用count()),部门的平均工资(avg(sal+comm))
    
    select d.deptno,dname,count(empno),avg(sal+comm) from dept d left join emp e on e.deptno = d.deptno group by d.deptno
    
  • 列出所有员工的姓名,部门名称和工资

    select ename,dname,sal+comm '工资' from emp e join dept d on e.deptno = d.deptno 
    
  • 列出所有部门的详细信息和部门人数

    select d.*,count(empno) from dept d left join emp e on e.deptno = d.deptno group by d.deptno
    
  • 列出各种工作的最低工资

    select job,min(sal+comm) from emp group by job  
    
  • 列出各个部门的manager的最低薪金(若是manager,其job的值为manageer)

    select e.deptno,dname,min(sal) from dept d join emp e on e.deptno = d.deptno where job = 'manager' group by e.deptno 
    
  • 列出受雇日期早于其直接上级的所有员工

    select e.*,mgr.hiredate from emp e join emp mgr on e.mgr = mgr.empno where e.hiredate < mgr.hiredate
    
  • 列出部门名称和这些部门的员工信息,同时列出那些没有员工的部门

    select dname,e.* from dept d left join emp e on e.deptno = d.deptno order by dname
    
  • 列出所有’clerk’(办事员)岗位的姓名以及部门名称

    select ename,dname from emp e  join dept d on e.deptno = d.deptno where job = 'clerk'
    
  • 列出最低薪资大于6500的各种工作

    select job from emp group by job having min(sal) > 6500
    
  • 列出在研发部工作的员工姓名,假定不知道研发部的部门编号

    select ename from dept d join emp e on e.deptno = d.deptno where dname = '研发部'
    

27.有以下表写出sql

  • 查询“语文”课程比“数学”课程成绩高的学生的性别及课程分数

    -- 查询语文成绩
    select sc.* from course c join score sc on c.c_id = sc.c_id where c_name = '语文'
    -- 查询数学成绩
    select sc.* from course c join score sc on c.c_id = sc.c_id where c_name = '数学'
    -- 以上两表和学生表进行连接查询,查询对应的学生数据(3表联查)
    select s.s_id,s_sname,s_sex,chinese.s_score '语文分',math.s_score '数学分' from student s join
    (select sc.* from course c join score sc on c.c_id = sc.c_id where c_name = '语文') chinese join
    (select sc.* from course c join score sc on c.c_id = sc.c_id where c_name = '数学') math 
    on chinese.s_id = math.s_id and chinese.s_score > math.s_score and s.s_id = math.s_id
    
  • 查询“语文”课程比“数学”课程成绩低的学生的性别及课程分数

    select s.s_id,s_sname,s_sex,chinese.s_score '语文分',math.s_score '数学分' from student s join
    (select sc.* from course c join score sc on c.c_id = sc.c_id where c_name = '语文') chinese join
    (select sc.* from course c join score sc on c.c_id = sc.c_id where c_name = '数学') math 
    on chinese.s_id = math.s_id and chinese.s_score < math.s_score and s.s_id = math.s_id
    
  • 查询平均成绩大于等于60分的学生的学生编号和学生姓名和平均成绩

    select s.s_id,s_name, avg(s_score) av from score sc join
    student s on sc.s_id=s.s_id group by sc.s_id having av >= 60
    
  • 查询平均成绩小于60分的学生的学生编号和学生姓名和平均成绩(包括有成绩和无成绩)

    -- 求出每个学生的总分 / 课程总数 = 平均分 然后筛选平均分 < 60 学生
    
    select s.s_id,s_name,sum(s_score)/(select count(*) from course) av from student s join score sc on s.s_id = sc.s_id group by sc.s_id having av < 60
    
  • 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩

    select s.s_id,s_name,count(c_id),sum(s_score) from student s left join score sc on s.s_id = sc.s_id group by s.s_id  
    
  • 查询“王”姓老师的数量

    select count(*) from teacher where t_name like '王%'
    
  • 查询学过“张三”老师授课的同学的信息

    select distinct s.* from teacher t join course c join score sc join student s on t.t_id = c.t_id and c.c_id = sc.c_id and sc.s_id = s.s_id where t_name = '张三'
    
  • 查询学过编号为“01”且也学过编号”02“课程的同学的信息

    select s.* from score sc1 join score sc2 join student s on sc1.s_id = sc2.s_id and sc1.s_id=s.s_id where sc1.c_id = '01'and sc2.c_id = '02'
    
  • 按平均成绩从高到低显示所有学生的所有课程的成绩及平均成绩

    -- 先求出每个学生的平均分(总分 / 课程总数) - 要求所有学生均要查,使用外连接查询
    select s.s_id,s_name,sum(s_score) / (select count(*) from course) av,
    (select sc1.s_score from score sc1 where sc1.c_id = '01' and sc1.s_id = s.s_id) '语文',
    (select sc2.s_score from score sc2 where sc1.c_id = '02' and sc2.s_id = s.s_id) '数学',
    (select sc3.s_score from score sc3 where sc1.c_id = '03' and sc3.s_id = s.s_id) '英语',
    from student s left join score sc on s.s_id = sc.s_id group by s.s_id order by av desc
    
  • 课程ID,课程name,最高分,最低分,平均分,及格率,中等率,优良率
    优秀率(及格为:>=60,中等为:70-80,优良为:80-90,优秀为:>=90)

    sum (case when s_score >= 60 then 1 else 0 end) / count(s_id) 
    
    select c.c_id,c_name,max(s_score) '最高分',min(s_score) '最低分',avg(s_score) '平均分',
    sum (case when s_score >= 60 then 1 else 0 end) / count(s_id) '及格率',
    sum (case when s_score >= 70 and s_score < 80 then 1 else 0 end) / count(s_id) '中等率',
    sum (case when s_score >= 80 and s_score < 90 then 1 else 0 end) / count(s_id) '优良率',
    sum (case when s_score >= 90 then 1 else 0 end) / count(s_id) '优秀率'
    from course c left join score sc on c.c_id = sc.c_id group by c.c_id
    
  • 查询每门科目成绩都在60分及以上的学生id,姓名,成绩

    select s.s_id,s_name , sc1.s_score'语文',sc2.s_score'数学' , sc3.s_score'英语' from score sc1 join score sc2 join score sc3 join student s on sc1.s_id = sc2.s_id and sc2.s_id = sc3.s_id and sc3.s_id = s.s_id where sc1.c_id = '01' and sc1.s_score >= 60 and sc2.c_id = '02' and sc2.s_score >= 60 and sc3.c_id = '03' and sc3.s_score >= 60
    
  • 查询至少有一门科目成绩在90分及以上的学生id,姓名,成绩

    select s.s_id,s_name,
    (select from score sc1 where sc1.c_id = '01' and sc1.s_id = s.s_id) '语文',
    (select from score sc2 where sc2.c_id = '02' and sc2.s_id = s.s_id) '数学',
    (select from score sc3 where sc3.c_id = '03' and sc3.s_id = s.s_id) '英语'
    from score sc join student s on sc.s_id = s.s_id group by sc.s_id having max(s_score) >=90
    
  • 查询所有科目成绩总和在240分及以上的学生id,姓名,和成绩总和,降序排列

    select s.s_id,s_name,SUM(s_score) sum from score sc join student s on sc.s_id = s.s_id group by sc.s_id having sum >= 240 order by sum desc
    
  • 查询每个科目成绩最高的学生的学生id,姓名,写在一个表上

    create table t as 
    select s.s_id,s_name,tmp.c_id,max from score sc join student s join (select c_id,MAX(s_score) max from score group by c_id) tmp on sc.c_id = tmp.c_id and sc.s_score = tmp.max and s.s_id = sc.s_id 
    
  • 查询每个科目成绩最低的学生的学生id,姓名

    select s.s_id,s_name,tmp.c_id,min from score sc join student s join
    (select c_id,min(s_score) min from score group by c_id)tmp on sc.c_id = tmp.c_id and sc.s_score = tmp.min and sc.s_id = s.s_id
    
  • 查询目前没有安排课程的老师的姓名

    -- 查询每个老师的课程数,筛选课程数为0的
    -- 方式1: 查询教课数为0的老师
    select t.t_id,t_name from teacher t left join course c on t.t_id = c.t_id group by t.t_id having count(c_id) = 0
    -- 方式2: 两表外联查询c_id为null的数据
    select t_name from teacher t left join course c on t.t_id = c.t_id where c_id is null
    
    
  • 将之前老师表的英文名字转化为大写

    update teacher set t_name = upper(t_name)
    
  • 查询每门课程最好的前两名

    -- 统计每个学生每门课程比其分数高的人数,筛选比其分数高的人数<2的数据,即当前这个学生是这门课程中的前2名
    
    select sc1.s_id,s_name,sc1.c_id,sc1.s_score from score sc1 join student s on sc1.s_id = s.s_id left join score sc2 on sc1.c_id = sc2.c_id and
    sc2.s_score > sc1.s_score group by sc1.s_id,sc1.c_id having count(sc2.s_id)<2 order by sc1.c_id
    
  • 统计各科成绩各分数段人数,课程编号,课程名称,【100-85】【85-70】【70-60】【60-0】及所占百分比

    select c.c_id,c_name,
    sum(case when s_score < 60 then 1 else 0 end) '[0-60]',
    sum(case when s_score >= 60 and s_score < 70 then 1 else 0 end) '[60-70]',
    sum(case when s_score >= 70 and s_score < 85 then 1 else 0 end) '[70-85]',
    sum(case when s_score >= 85 then 1 else 0 end) '[85-100]',
    sum(case when s_score < 60 then 1 else 0 end) / count(s_id) '不及格率',
    sum(case when s_score >= 60 and s_score < 70 then 1 else 0 end) / count(s_id) '中等率',
    sum(case when s_score >= 70 and s_score < 85 then 1 else 0 end) / count(s_id) '良好率',
    sum(case when s_score >= 85 then 1 else 0 end) / count(s_id) '优秀率',
    from course c left join score sc on c.c_id = sc.c_id group by c.c_id
    
  • 查询学生表中的姓名重复的姓名

    select s_name from student group by s_name having count(*) > 1
    
  • 查询学生表中的姓名重复的所有学生信息

    select * from student where s_name in (select s_name from student group by s_name having count(*) > 1)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天你学Java了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值