精华内容
下载资源
问答
  • 最近新项目又使用了jpa。 对JPA简直又爱又恨。。。...根据方法名字生成SQL语句(根据方法名查询) public interface UserRepository extends Repository<User, Long> { List<User&g...

    最近新项目又使用了jpa。

    对JPA简直又爱又恨。。。基本能满足了所有的基本查询,还基本不用写sql语句,但是。。。。弊端就不说了吧。

    下面来详细看下支持的查询方式。

    根据方法名字生成SQL语句(根据方法名查询)

    public interface UserRepository extends Repository<User, Long> {
    
    List<User> findByEmailAddressAndLastname(String emailAddress, String lastname);
    }

     

    我们将使用JPA criteria API 创建一个查询,但本质上这转换为以下查询:

    select u from User u where u.emailAddress = ?1 and u.lastname = ?2

    Spring Data JPA将执行属性检查并遍历属性表达式中描述的嵌套属性。下面是 JPA 支持的关键字的概述,以及包含该关键字的方法的本质含义。

    SQL关键词想细介绍

    关键词DemoJPQL 语句片段
    AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
    OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
    Is,EqualsfindByFirstname,
    findByFirstnameIs,
    findByFirstnameEquals
    … where x.firstname = ?1
    BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
    LessThanfindByAgeLessThan… where x.age < ?1
    LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
    GreaterThanfindByAgeGreaterThan… where x.age > ?1
    GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
    AfterfindByStartDateAfter… where x.startDate > ?1
    BeforefindByStartDateBefore… where x.startDate < ?1
    IsNullfindByAgeIsNull… where x.age is null
    IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
    LikefindByFirstnameLike… where x.firstname like ?1
    NotLikefindByFirstnameNotLike… where x.firstname not like ?1
    StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
    EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
    ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
    OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
    NotfindByLastnameNot… where x.lastname <> ?1
    InfindByAgeIn(Collection<Age> ages)… where x.age in ?1
    NotInfindByAgeNotIn(Collection<Age> age)… where x.age not in ?1
    TruefindByActiveTrue()… where x.active = true
    FalsefindByActiveFalse()… where x.active = false
    IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

    超级全,自己可以各种尝试。

    展开全文
  • 查询选修了全部课程的学生姓名

    千次阅读 2021-02-05 12:30:02
    EXISTS 子查询找到的提交NOT EXISTS 子查询中 找不到的提交说明:不要去翻译为存在和不存在,把脑袋搞晕。2 。 建立程序循环的概念,这是一个动态的查询过程。如 FOR循环 。3 。 Exists执行的流程Exists首先执行...

    首先头脑中有三点概念:

    1 。  EXISTS 子查询找到的提交

    NOT EXISTS 子查询中 找不到的提交

    说明:不要去翻译为存在和不存在,把脑袋搞晕。

    2 。 建立程序循环的概念,这是一个动态的查询过程。如 FOR循环 。

    3 。 Exists执行的流程Exists首先执行外层查询,再执行内存查询,与IN相反。 流程为首先取出外

    层中的第        一  元组, 再执行内层查询,将外层表的第一元组代入,若内层查询为真,即有结果

    时。返回外层表中的第一元 组,接着取出第二元组,执行相同的算法。一直到扫描完外层整表 。

    for(int i =0;  i<>EOFout;i++)

    {

    for (int j = 0 ; j

    }

    然后再来看一个例子: 三张表  学生表student (Sno,Sname),  课程表course (Cno,Cname) 选课表SC

    (Sno,Cno)

    要求查询出 :选修了全部课程的学生姓名

    我的思路:

    首先学生的选课信息存在于SC表中, 要想知道某个学生是否选修了全部课程,至少我们需要知道一共有

    几门课程,这是首要的条件。其次,学生选修了与否,我们又要扫描SC全表,统计出选修了所有课程的

    学生号,最后在STUDENT表中根据学生号打出姓名 。

    语句如下:  (已测试)

    select Sname from student

    where Sno IN

    (select Sno from SC

    group by Sno //根据Sno分组,统计每个学生选修了几门课程。如果等于course的总数,就是我们要找的Sno

    having count(*) = (select count(*) from course ))    //统计course中共有几门课程

    另一种思路:

    引入:将题目换为 查找学号为 00003 没有选修的科目

    思路:我们可以将已知学号代入,把每一个科目代入(循环),这将形成1*count(*)种组合。

    将这组成作为条件,一一与SC表种进行比对,找不到匹配的我们提交 。

    select Cname from course  where

    not exists               //找不到的组合,提交course

    (select * from SC where course.cno = cno and sno = ''00002'')

    //在SC中匹配

    换个题目: 查找没有 没有选修科目的学生姓名

    思路:学号未知 , 科目未知,说明有两个未知变量。应该有两个EXISTS。我们可以扫描

    student 和 course共有 s * c 中组合,将这些组合与SC的每一项进行匹配,注意s*c组合已经包含所

    有可能。如果全部找到 ,就说明已经选修了全部课程。找不到就说明有课程没选修 。再将没选修的的

    提交给上一exists 循环 。若上一exists 不存在的再提交给外循环。

    select Sname from student

    where NOT exists        //

    (select  * from course

    where NOT exists      //不存在的提交给course

    (select * from SC where

    Sno = student.sno  and cno = Course.Cno))   // 代入两个未知变量

    回头看,就是我们第一个引出的题目:

    选修了全部课程的学生姓名

    首先头脑中有三点概念:

    1 。 EXISTS 子查询找到的提交

    NOT EXISTS 子查询中 找不到的提交

    说明:不要去翻译为存在和不存在,把脑袋搞晕。

    2 。 建立程序循环的概念,这是一个动态的查询过程。如 FOR循环 。

    3 。 Exists执行的流程Exists首先执行外层查询,再执行内存查询,与IN相反。 流程为首先取出外

    层中的第一元组, 再执行内层查询,将外层表的第一元组代入,若内层查询为真,即有结果

    时。返回外层表中的第一元 组,接着取出第二元组,执行相同的算法。一直到扫描完外层整表 。

    for(int i =0; i<>EOFout;i++)

    {

    for (int j = 0 ; j

    }

    然后再来看一个例子: 三张表 学生表student (Sno,Sname), 课程表course (Cno,Cname) 选课表SC

    (Sno,Cno)

    要求查询出 :选修了全部课程的学生姓名

    我的思路:

    首先学生的选课信息存在于SC表中, 要想知道某个学生是否选修了全部课程,至少我们需要知道一共有

    几门课程,这是首要的条件。其次,学生选修了与否,我们又要扫描SC全表,统计出选修了所有课程的

    学生号,最后在STUDENT表中根据学生号打出姓名 。

    语句如下: (已测试)

    select Sname from student

    where Sno IN

    (select Sno from SC

    group by Sno //根据Sno分组,统计每个学生选修了几门课程。如果等于course的总数,就是我们要找的Sno

    having count(*) = (select count(*) from course ))    //统计course中共有几门课程

    另一种思路:

    引入:将题目换为 查找学号为 00003 没有选修的科目

    思路:我们可以将已知学号代入,把每一个科目代入(循环),这将形成1*count(*)种组合。

    将这组成作为条件,一一与SC表种进行比对,找不到匹配的我们提交 。

    select Cname from course where

    not exists               //找不到的组合,提交course

    (select * from SC where course.cno = cno and sno = ''00003'')

    //在SC中匹配

    换个题目: 查找没有 没有选修科目的学生姓名

    思路:学号未知 , 科目未知,说明有两个未知变量。应该有两个EXISTS。我们可以扫描

    student 和 course共有 s * c 中组合,将这些组合与SC的每一项进行匹配,注意s*c组合已经包含所

    有可能。如果全部找到 ,就说明已经选修了全部课程。找不到就说明有课程没选修 。再将没选修的的

    提交给上一exists 循环 。若上一exists 不存在的再提交给外循环。

    最后详细回答你的问题:数据库SQL语句中 查询选修了全部课程的学生的学号和姓名

    查询选修了全部课程的学生姓名。

    SELECT Sname

    FROM Student

    WHERE NOT EXISTS

    (SELECT *

    FROM Course

    WHERE NOT EXISTS

    (SELECT *

    FROM SC

    WHERE Sno= Student.Sno

    AND Cno= Course.Cno);

    理解如下:    查询选修了全部课程的学生姓名。

    不用管怎么样,第一个select 必定是在 student 表里选 sname 既:

    SELECT Sname

    FROM Student

    加上条件即: where

    条件是什么呢? 条件就是---------------------》 查询选修了全部课程的

    因为没有    (任意一个)谓词, 只能用  EXISTS   或者  NOT EXISTS 来表示。 这点理解吧?

    所以要把条件翻译成 -----------------------》  不存在一门课程这个学生没有选修

    where后面就是  不存在(NOT EXISTS) (

    一门课程这个学生没有选修

    )

    接下来就是把Course表中的课程依次拿出来找出 没有选修的

    怎么找呢?  因为  NOT EXISTS 子查询中 找不到的提交

    另外你要明白 ----------------------------NOT EXISTS 查询 都是相关查询----------

    所以只要把 在最后一个select 中

    WHERE Sno= Student.Sno

    AND Cno= Course.Cno);

    就是将这个同学通过 SC 表 和  Crouse的 课程连接一遍,找到连接不上的,即: 没有选修的,  这样就找到了一门课这个学生没有选修, 存在没有选修的课,那么该学生被pass掉了,

    一次进行一个同学的判断  。

    若你学过程序编程,可以看下面的内容, 若没有则可忽略、。----------

    上述是理解是数据库系统内部的实现,可以用for循环表示

    for(i=1; i

    for(i=j;j

    条件就是:

    没有一门课没有选修

    }

    }

    最后你找记住

    1. 第一个select 就是 你要选的就是    学生

    SELECT Sname

    FROM Student

    2. 第二个 select 就是  课程

    3.  第三个select 就是  学生和课程发生关系的表 ------------SC选修表

    让他们连接起来

    固定的模式 1 你要的结果的表  学生

    2  满足条件的表   课程表

    3  产生关系的表   选修表

    where    通过选修表把他们连接起来

    ============================

    查询select----存在量词查询

    exists代表存在量词ョ,该查询结果没有值,只有逻辑值真true和逻辑假false两个值。

    ex41:查询所有选修了001课程的学生名单

    select sname

    from student a

    where exists (

    select *

    from sc b

    where a.sno=b.sno and cno='001')

    ex42:查询没有选修了001课程的学生名单

    select sname

    from student a

    where not exists (

    select *

    from sc b

    where a.sno=b.sno and cno='001')

    ex43:查询选修了所有课程的学生名单。

    由于SQL中没有全称量词,可以这样理解:查询这样的学生,没有一门课程他没有选

    select sname

    from student a

    where not exists (

    select *

    from course b

    where not exists (

    select *

    from sc c

    where a.sno=c.sno and c.cno=b.cno))

    注意:SQL没有蕴涵谓词,可以使用等价变换进行转换

    p→q ≡ ┑p∨q

    ex43:查询至少选修了学生95002选修的全部课程的学生名单。

    将查询进行变换:

    p表示的谓词:95002选修了课程y

    q表示的谓词:学生x选修了课程y

    该查询转换为:( y)p→q

    进一步转换:( y)p→q ≡

    ┑(ョy( ┑(p→q))) ≡ ┑(ョy( ┑(┑p∨q)))

    ≡ ┑ョy(p∧q) 德模根定律

    它所表达的含义为:不存在这样的课程y,95002选修了y而x没有选,SQL语句如下:

    select sname,sno

    from student a

    where sno <> '95002' and not exists (

    select *

    from sc b

    where sno='95002' and not exists (

    select *

    from sc c

    where a.sno=c.sno and c.cno=b.cno))

    展开全文
  • ” 在清单2中,我创建了六个对象,将它们放入文件中,然后使用QBE调用名字与模式“ Brian”匹配的两个对象。 这种查询风格使用原型对象(传递给get()调用的原型对象)来确定数据库中的对象是否匹配,并返回那些符合...

    本系列第一篇文章中,我讨论了RDBMS作为Java™对象存储解决方案的失败。 正如我所解释的那样,在当今的面向对象的世界中,像db4o这样的对象数据库可以为面向对象的开发人员提供更多的功能,而不仅仅是关系数据库。

    在本文和以后的文章中,我将继续介绍对象数据库。 我将使用示例来展示存储系统的强大功能,该存储系统针对您在选择的面向对象编程语言(在本例中为Java语言)中使用的相同“形状”实体进行了优化。 特别是,我将介绍各种可用于将对象检索,修改和还原回db4o的机制。 正如您将学到的,一旦您摆脱了SQL的约束,您可以做的事实际上令人惊讶。

    如果尚未这样做,则可能要立即下载db4o 。 您需要它来编译示例。

    实例查询

    示例查询(QBE)是一种数据库查询语言,它允许您通过设计要进行比较的“模板”来创建查询,而不是使用谓词条件的语言(如SQL)。 我上次演示了使用db4o的QBE引擎进行数据检索,但是在这里我将快速回顾一下。 首先看一下我公认的原始数据库。 它由一种类型组成,其定义如清单1所示:

    清单1. Person类
    package com.tedneward.model;
    
    public class Person
    {
        public Person()
        { }
        public Person(String firstName, String lastName, int age)
        {
            this.firstName = firstName;
            this.lastName = lastName;
            this.age = age;
        }
        
        public String getFirstName() { return firstName; }
        public void setFirstName(String value) { firstName = value; }
        
        public String getLastName() { return lastName; }
        public void setLastName(String value) { lastName = value; }
        
        public int getAge() { return age; }
        public void setAge(int value) { age = value; }
    
        public String toString()
        {
            return 
                "[Person: " +
                "firstName = " + firstName + " " +
                "lastName = " + lastName + " " +
                "age = " + age + 
                "]";
        }
        
        public boolean equals(Object rhs)
        {
            if (rhs == this)
                return true;
            
            if (!(rhs instanceof Person))
                return false;
            
            Person other = (Person)rhs;
            return (this.firstName.equals(other.firstName) &&
                    this.lastName.equals(other.lastName) &&
                    this.age == other.age);
        }
        
        private String firstName;
        private String lastName;
        private int age;
    }

    随着POJO的发展, Person几乎不是一个复杂的野兽。 它由三个字段和一些支持类似于POJO的活动的基本方法组成,即toString()equals() 。 (约书亚·布洛赫(Joshua Bloch)的《 有效Java》的精明读者会注意到,我省略了hashCode()实现,这明显违反了规则8。在经典的作者看来,我将hashCode()留为“对读者的一种练习, “这通常意味着作者要么不想打扰它,要么认为手头的例子不必要。我也把它留给读者作为练习,以决定在这里是哪种情况。”

    在清单2中,我创建了六个对象,将它们放入文件中,然后使用QBE调用名字与模式“ Brian”匹配的两个对象。 这种查询风格使用原型对象(传递给get()调用的原型对象)来确定数据库中的对象是否匹配,并返回那些符合条件的对象的ObjectSet (本质上是一个集合)。

    清单2.通过示例查询
    import com.db4o.*;
    
    import com.tedneward.model.*;
    
    public class Hellodb4o
    {
        public static void main(String[] args)
            throws Exception
        {
            ObjectContainer db = null;
            try
            {
                db = Db4o.openFile("persons.data");
    
                Person brian = new Person("Brian", "Goetz", 39);
                Person jason = new Person("Jason", "Hunter", 35);
                Person brians = new Person("Brian", "Sletten", 38);
                Person david = new Person("David", "Geary", 55);
                Person glenn = new Person("Glenn", "Vanderberg", 40);
                Person neal = new Person("Neal", "Ford", 39);
                
                db.set(brian);
                db.set(jason);
                db.set(brians);
                db.set(david);
                db.set(glenn);
                db.set(neal);
    
                db.commit();
                
                // Find all the Brians
                ObjectSet brians = db.get(new Person("Brian", null, 0));
                while (brians.hasNext())
                    System.out.println(brians.next());
            }
            finally
            {
                if (db != null)
                    db.close();
            }
        }
    }

    查询规则

    由于QBE使用原型对象作为其模板来搜索数据,因此有一些关于其用法的简单规则。 当db4o正在为给定目标搜索“ Person类型的所有对象时(发生的事情过于简化,但从概念上讲是准确的),以确定数据存储中的特定对象是否符合条件,将字段值一一比较。 如果原型中的字段为“ null”,则该值与数据存储区中的任何值匹配;否则为0。 否则,值必须完全匹配。 对于基本类型,由于基本类型不能真正保存“ null”值,因此零用作通配符值。 (这也指出了QBE方法的局限性-不能有效地使用零作为搜索值。)如果指定了多个字段值,则数据库中的对象必须满足候选人的所有字段值对象符合查询条件; 从本质上讲,这意味着将字段“与”在一起以形成查询谓词。

    在前面的示例中,查询正在查找firstName字段等于“ Brian”且有效忽略了lastNameage字段的所有Person类型。 在表中,此调用将大致对应于SELECT * FROM Person WHERE firstName = "Brian"SQL查询。 (但是,要谨慎尝试将OODBMS查询映射到SQL:这种类比并不完美,并且可能导致对特定查询的性质和性能的误解。)

    查询返回的对象是ObjectSet ,它与JDBC ResultSet相似,因为它是对象的简单容器。 使用ObjectSet实现的Iterator接口,对结果进行ObjectSet是一个简单的练习。 使用Person的特定方法将需要对next()返回的对象进行向下转换。

    更新和身份

    尽管简单的数据显示本身很有趣,但是大多数对象也需要进行修改并将其还原回数据库。 这可能是使用OODBMS的最棘手的部分,因为对象数据库使用的标识概念与关系数据库使用的标识概念不同。 实际上,这意味着在使用对象数据库时,必须更加注意内存中的对象与存储中的对象。

    清单3中的简单示例演示了身份的不同概念:

    清单3.三个布莱恩斯
    import com.db4o.*;
    
    import com.tedneward.model.*;
    
    public class Hellodb4o
    {
        public static void main(String[] args)
            throws Exception
        {
            ObjectContainer db = null;
            try
            {
                db = Db4o.openFile("persons.data");
    
                Person brian = new Person("Brian", "Goetz", 39);
                Person jason = new Person("Jason", "Hunter", 35);
                Person brians = new Person("Brian", "Sletten", 38);
                Person david = new Person("David", "Geary", 55);
                Person glenn = new Person("Glenn", "Vanderberg", 40);
                Person neal = new Person("Neal", "Ford", 39);
                
                db.set(brian);
                db.set(jason);
                db.set(brians);
                db.set(david);
                db.set(glenn);
                db.set(neal);
    
                db.commit();
                
                // Find all the Brians
                ObjectSet brians = db.get(new Person("Brian", null, 0));
                while (brians.hasNext())
                    System.out.println(brians.next());
                    
                Person brian2 = new Person("Brian", "Goetz", 39);db.set(brian2);db.commit();
    
                // Find all the Brians
                ObjectSet brians = db.get(new Person("Brian", null, 0));
                while (brians.hasNext())
                    System.out.println(brians.next());
            }
            finally
            {
                if (db != null)
                    db.close();
            }
        }
    }

    当您运行清单3中的查询时,数据库报告三个Brian ,其中两个Brian Goetz。 (如果person.data文件已经存在于当前目录中,则会产生类似的效果-创建的所有Person都将存储在person.data文件中,并且存储在其中的所有Brian都将由查询返回。 )

    显然,关于主键的旧规则在这里并没有生效; 那么对象数据库如何处理唯一性概念?

    拥抱OID

    将对象存储到对象数据库中时,将创建一个唯一键,称为对象标识符或OID (与最后一个回避音节的发音类似),它唯一地标识该对象。 除非明确请求,否则OID就像C#和Java编程中的this指针/引用一样,是无声的。 在db4o中,可以通过调用db.ext().getID()找到给定对象的OID。 (您还可以使用db.ext().getByID()方法通过OID检索对象。调用此方法的含义有些复杂,因此此处db.ext().getByID()讨论,但仍然可以选择。)

    实际上,所有这些意味着开发人员可以通过先前在容器中查询该对象来确定对象是否存在于系统中,如清单4所示:

    清单4.插入之前的查询
    // ... as before
            ObjectContainer db = null;
            try
            {
                db = Db4o.openFile("persons.data");
                
                ...
    
                // We want to add Brian Goetz to the database; is he already there?
                if (db.get(new Person("Brian", "Goetz", 0).hasNext() == false)
                {
                    // Nope, no Brian Goetz here, go ahead and add him
                    db.set(new Person("Brian", "Goetz", 39));
                    db.commit();
                }
            }

    在这种特殊情况下,我们假设一个Person在系统中的唯一性是其名字-姓氏组合。 因此,在数据库中搜索Brian时,只需在Person实例上查找那些属性。 (也许布莱恩是在几年前加入的,那时他才39岁。)

    如果要修改数据库中的对象,可以很简单地从容器中检索对象,以某种方式对其进行修改,然后再将其存储回去,如清单5所示:

    清单5.更新对象
    // ... as before
            ObjectContainer db = null;
            try
            {
                db = Db4o.openFile("persons.data");
                
                ...
    
                // Happy Birthday, David Geary!
                if ((ObjectSet set = db.get(new Person("David", "Geary", 0))).hasNext())
                {
                    Person davidG = (Person)set.next();davidG.setAge(davidG.getAge() + 1);db.set(davidG);db.commit();
                }
                else
                    throw new MissingPersonsException(
                        "David Geary doesn't seem to be in the database");
            }

    db4o容器在这里不会遇到身份问题,因为相关对象已被识别为来自数据库的对象,这意味着其OID已存储在db4o簿记基础结构中。 因此,当您调用set ,db4o知道更新现有对象而不是插入新对象。

    搜索实用程序方法

    尽管不是QBE固有的,但特定于应用程序的主键的概念还是值得保留的。 您需要一种实用程序方法来简化基于身份的搜索。 本节向您展示了一种基于解决方案的解决方案,该解决方案使用了Reflection API在正确的字段中戳入正确的值,并提出了针对各种喜好和美感来调整解决方案的方法。

    让我们从一个基本前提开始:我有一个db4o数据库,其中有一个我要基于其中具有某些值的字段集进行查询的类型( Person )。 在此方法中,我使用Class上的Reflection API来创建该类型的新实例(调用其默认构造函数)。 然后,我遍历其中包含字段的字符串数组,以获取Class中的每个Field对象。 之后,我遍历与每个字段的值相对应的对象数组,然后调用Field.set()将那个值Field.set()我的模板对象中。

    完成这些操作后,我在db4o数据库上调用get()并检查返回的ObjectSet是否包含任何对象。 这给了我一个基本的方法概述,如清单6所示:

    清单6.用于执行QBE身份搜索的实用程序方法
    import java.lang.reflect.*;
    import com.db4o.*;
    
    public class Util
    {
        public static boolean identitySearch(ObjectContainer db, Class type,
            String[] fields, Object[] values)
                throws InstantiationException, IllegalAccessException,
                    NoSuchFieldException
        {
                // Create an instance of our type
                Object template = type.newInstance();
                
                // Populate its fields with the passed-in template values
                for (int i=0; i<fields.length; i++)
                {
                    Field f = type.getDeclaredField(fields[i]);
                    if (f == null)
                        throw new IllegalArgumentException("Field " + fields[i] + 
                            " not found on type " + type);
                    if (Modifier.isStatic(f.getModifiers()))
                        throw new IllegalArgumentException("Field " + fields[i] + 
                            " is a static field and cannot be used in a QBE query");
                    f.setAccessible(true);
                    f.set(template, values[i]);
                }
                
                // Do the query
                ObjectSet set = db.get(template);
                if (set.hasNext())
                    return true;
                else
                    return false;
        }
    }

    显然,可以做很多工作来调整此方法的味道,例如捕获所有异常类型并将它们作为运行时异常重新抛出,或者返回ObjectSet本身而不是true / false ,甚至返回包含以下内容的对象数组: ObjectSet内容(这将使检查返回数组的长度变得容易)。 但是,从清单7中可以明显看出,它的用法比已经显示的基本QBE版本简单得多:

    清单7.工作中的实用程序方法
    // Is Brian already in the database?
    if (Util.identitySearch(
        db, Person.class, {"firstName", "lastName"}, {"Brian", "Goetz"}) == false)
    {
        db.set(new Person("Brian", "Goetz", 39));
        db.commit();
    }

    实际上,当将实用程序方法的许多实用程序放置在存储的类本身上时,它们就会变得很明显,如清单8所示:

    清单8.在Person内部使用Utility方法
    public class Person
    {
        // ... as before
        
        public static boolean exists(ObjectContainer db, Person instance)
        {
            return (Util.identitySearch(db, Person.class,
                {"firstName", "lastName"},
                {instance.getFirstName(), instance.getLastName()});
        }
    }

    或者,再次,您可以调整方法以返回找到的实例,以使Person实例具有适当关联的OID,依此类推。 要记住的关键是,您可以在db4o基础结构之上构建便捷方法,以使其易于使用。

    请注意,使用db4o SODA查询API可以对存储在磁盘上的基础对象执行这种查询样式,这是一种更有效的方法,但是它在本文的讨论范围之外,因此我将其留待以后的讨论。

    高级查询

    到目前为止,您已经了解了如何查询单个对象或满足特定条件的对象。 尽管这使发出查询的方法相当容易,但也使选择受到了限制。 例如,如果你需要什么样的检索所有Person (胡)的名字开始与G,或所有Person的年龄大于21号第? 对于这些类型的查询,QBE方法将严重失败,因为QBE进行相等匹配而不是比较。

    从历史上看,即使是比较复杂的比较也一直是OODBMS的弱点,也是关系模型和SQL的强项。 在SQL中发出比较查询很简单,但是要在OODBMS中执行相同的查询,则需要采用几种不引人注意的方法之一:

    • 获取所有对象并自己进行相对比较。
    • 扩展QBE API以包括谓词。
    • 创建查询语言以将其转换为针对您的对象模型的查询。

    比较弱

    显然,上面的第一个选项仅对最普通的数据库才可行,因为它给您可以实际使用的数据库大小增加了明显的上限。 即使最坚硬的硬件也无法轻易摆脱百万个对象的负担,尤其是在通过网络连接的情况下。 (顺便说一下,这并不是对OODBMS的起诉-通过RDBMS服务器的能力可以通过网络连接获取一百万行,但仍会破坏其所在的网络。)

    第二种选择污染了QBE方法的简单性,并导致了清单9中所示的怪异现象:

    清单9.带有谓词的QBE调用
    Query q = new Query();
    q.setClass(Person.class);
    q.setPredicate(new Predicate(
        new And(
            new Equals(new Field("firstName"), "David"),
            new GreaterThan(new Field("age"), 21)
        )));
    q.Execute();

    很容易看出使用这种技术,任何中等复杂的查询将如何Swift变得不可行,特别是与诸如SQL之类的查询语言相比时。

    第三种选择是创建一种查询语言,然后该查询语言可用于查询数据库的对象模型。 过去,OODBMS员工创建了标准查询语言,对象查询语言或OQL,其外观类似于清单10:

    清单10. OQL的片段
    SELECT p FROM Person
    WHERE p.firstName = "David" AND p.age > 21

    从表面上看,OQL看起来与SQL非常相似,因此据说同样强大且易于使用。 OQL的缺点是它想返回……什么? 类似于SQL的语言似乎像SQL一样想要返回列集(元组),但是对象数据库不能那样工作-它想要返回对象,而不是任意集。 特别是在像C#或Java编程这样的强类型语言中,这些对象类型必须先验地知道 ,这与基于集合SQL概念不同。

    db4o中的本机查询

    db4o并没有强迫开发人员使用复杂的查询API或引入新的“ something-QL”,而是提供了一种称为本机查询的功能 ,该功能既强大又非常易于使用,如清单11所示。对于db4o的API 是 SODA查询,这是主要用于细粒度查询控制的形式提供。正如你在第二个看不过来,SODA通常只用于手动优化查询必要的。)

    清单11. db4o本机查询
    // ... as before
            ObjectContainer db = null;
            try
            {
                db = Db4o.openFile("persons.data");
                
                ...
    
                // Who wants to get a beer?
                List<Person> drinkers = db.query(new Predicate<Person>() {
                    public boolean match(Person candidate) {
                        return person.getAge() > 21;
                    }
                }
                for (Person drinker : drinkers)
                    System.out.println("Here's your beer, " + person.getFirstName());
            }

    查询的“本机”部分是这样的事实:它是用编程语言本身(在这种情况下是Java语言)编写的,而不是用某种任意的语言编写的,然后必须将其翻译成其他某种语言。 (Predicate API的非泛型版本可用于Java 5之前的版本,尽管使用起来不太容易。)

    片刻考虑一下,您可能会开始怀疑这种特定方法是如何实施的。 或者必须使用源预处理器将其中包含查询的源文件转换为数据库引擎可以理解的内容( 例如 SQL / J或其他嵌入式预处理器),或者数据库会将所有Person对象发送回给对整个集合执行谓词的客户端(换句话说,就是之前拒绝的方法)。

    事实证明,db4o均不执行任何操作。 相反,db4o背后的负责人选择对本地查询采用一种有趣且创新的方法。 松散地说,db4o系统将一个谓词发送到数据库,在数据库中它在运行时对match()方法的字节码执行字节码分析。 如果字节码足够容易理解,db4o会将该查询转换为SODA查询以提高效率,在这种情况下,无需实例化所有对象以传递给match()方法。 这样,程序员可以继续使用自己喜欢的语言编写查询,但是查询本身可以转换为数据库可以理解和有效执行的内容。 (如果愿意的话,可以选择“ JQL” - Java查询语言。但是,请不要对db4o开发人员重复该名称;否则会给我带来麻烦。)

    让db4o告诉您...

    本机查询方法并不完美。 例如,完全有可能编写一个足以打败字节码分析器的本机查询,从而需要执行最坏情况的执行模型。 在这种最坏的情况下,db4o必须实例化数据库中查询类型的每个对象,并将每个对象都通过match()实现。 可以预计,这会降低查询性能,但是您可以通过在需要的地方安装侦听器来解决此问题。

    直觉并不总是足以预见优化失败,因为原因可能与代码审查所暗示的完全不同。 例如,在控制台代码中包含控制台打印语句(Java代码中为System.out.println或C#中包含System.Console.WriteLine )会导致优化器在db4o的.NET版本中失败,而Java版本会优化该语句。 您无法真正预料到这种类型的变化(尽管您可以通过经验来了解它们),所以让系统告诉您总是一个好主意,就像他们在极限编程中所说的那样。

    只需在ObjectContainer本身上注册一个侦听器( Db4oQueryExecutionListener ),以通知您是否无法优化本机查询,如清单12所示:

    清单12. DiagnosticListener
    // ... as before
            ObjectContainer db = null;
            try
            {
                db = Db4o.openFile("persons.data");
                
                db.ext().configure().diagnostic().addListener(new DiagnosticListener() {
                    public void onDiagnostic(Diagnostic d) {
                        if (d instanceof NativeQueryNotOptimized)
                        {
                            // could display information here, but for simplicity
                            // let's just fail loudly
                            throw new RuntimeException("Native query failed optimization!");
                        }
                    }
                });
            }

    显然,这仅在开发过程中是合乎需要的-在运行时,最好将此故障记录到log4j错误流或对用户分心的东西。

    结论

    在《繁忙的Java开发人员db4o指南》的第二篇文章中,我将OODBMS身份概念用作解释db4o如何存储和检索对象以及引入其本机查询功能的起点。

    QBE是用于简单查询情况的首​​选机制,因为它是一种更易于使用的API,但是它确实要求您的域对象允许将包含数据的任何或所有字段设置为null,这可能会违反您的某些域规则。 例如,能够为Person对象强制使用名字和姓氏将是很好的。 但是,在QBE查询中仅使用Person作为姓氏,就要求将名字允许为空,这实际上意味着我们必须选择域约束或查询功能,而这两者都不是完全可以接受的。

    本机查询提供了执行复杂查询的强大方法,而无需学习新的查询语言或诉诸复杂的对象结构来对谓词建模。 对于db4o的本机查询工具无法满足需求的情况,SODA API(最初显示为任何对象系统的独立查询系统,并且仍然存在于SourceForge上)使您可以将查询调优至最细微的细节,以简单为代价。

    这种多方面的数据库查询方法可能会让您感到复杂和混乱,并且与RDBMS的工作方式完全不同。 实际上,情况并非如此:大多数大型数据库将SQL文本转换为字节码格式,然后对其进行分析和优化,然后针对存储在磁盘上的数据执行,组合回文本并返回。 db4o本机查询方法将编译后的字节码重新交到Java(或C#)编译器手中,从而允许类型安全和更早地检测到错误的查询语法。 (顺便说一下,遗憾的是,JDBC访问SQL的方法中缺少类型安全性,因为它是一个调用级接口,因此仅限于只能在运行时检查的字符串。这对任何CLI都是如此,而不仅仅是JDBC; ODBC和.NET的ADO.NET受到相同的限制。)优化仍在数据库内部完成,但不是将文本返回,而是将真实对象发回,以备使用。 这与SQL / Hibernate或其他ORM方法形成鲜明对比,Esther Dyson著名地描述了以下方法:

    使用桌子存放物品就像开车开车然后将其分解以放入车库一样。 它可以在早上再次组装,但最终有人问这是否是最有效的停车方式。

    确实。 下次见。


    翻译自: https://www.ibm.com/developerworks/java/library/j-db4o2/index.html

    展开全文
  • 在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,...

    转自:https://www.cnblogs.com/xuanzhi201111/p/4175635.html

    MySQL Explain详解

    在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。(QEP:sql生成一个执行计划query Execution plan)

    mysql> explain select * from servers;
    +----+-------------+---------+------+---------------+------+---------+------+------+-------+
    | id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |
    +----+-------------+---------+------+---------------+------+---------+------+------+-------+
    |  1 | SIMPLE      | servers | ALL  | NULL          | NULL | NULL    | NULL |    1 | NULL  |
    +----+-------------+---------+------+---------------+------+---------+------+------+-------+
    1 row in set (0.03 sec)

    expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra,下面对这些字段出现的可能进行解释:

    一、 id

         我的理解是SQL执行的顺序的标识,SQL从大到小的执行

    1. id相同时,执行顺序由上至下

    2. 如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行

    3.id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行

     

     

    二、select_type

          示查询中每个select子句的类型

    (1) SIMPLE(简单SELECT,不使用UNION或子查询等)

    (2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)

    (3) UNION(UNION中的第二个或后面的SELECT语句)

    (4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

    (5) UNION RESULT(UNION的结果)

    (6) SUBQUERY(子查询中的第一个SELECT)

    (7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)

    (8) DERIVED(派生表的SELECT, FROM子句的子查询)

    (9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

     

    三、table

    显示这一行的数据是关于哪张表的,有时不是真实的表名字,看到的是derivedx(x是个数字,我的理解是第几步执行的结果)

     

    mysql> explain select * from (select * from ( select * from t1 where id=2602) a) b;
    +----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
    | id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |
    +----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
    |  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
    |  2 | DERIVED     | <derived3> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
    |  3 | DERIVED     | t1         | const  | PRIMARY,idx_t1_id | PRIMARY | 4       |      |    1 |       |
    +----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

     

     

    四、type

    表示MySQL在表中找到所需行的方式,又称“访问类型”。

    常用的类型有: ALL, index,  range, ref, eq_ref, const, system, NULL(从左到右,性能从差到好)

    ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

    index: Full Index Scan,index与ALL区别为index类型只遍历索引树

    range:只检索给定范围的行,使用一个索引来选择行

    ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

    eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

    const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system

    NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

     

    五、possible_keys

    指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

    该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。
    如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询

     

    六、Key

    key列显示MySQL实际决定使用的键(索引)

    如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

     

    七、key_len

    表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)

    不损失精确性的情况下,长度越短越好 

     

    八、ref

    表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

     

    九、rows

     表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数

     

    十、Extra

    该列包含MySQL解决查询的详细信息,有以下几种情况:

    Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤

    Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询

    Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”

    Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。

    Impossible where:这个值强调了where语句会导致没有符合条件的行。

    Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行

     

     

    总结:
    • EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
    • EXPLAIN不考虑各种Cache
    • EXPLAIN不能显示MySQL在执行查询时所作的优化工作
    • 部分统计信息是估算的,并非精确值
    • EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。

     

    参考资料:http://dev.mysql.com/doc/refman/5.5/en/explain-output.html

                    http://www.cnitblog.com/aliyiyi08/archive/2008/09/09/48878.html

                    http://www.cnblogs.com/gomysql/p/3720123.html

    展开全文
  • 【其它】查询计算机系未选课的学生学号和姓名【其它】编写触发器,在SC表中,不能将不及格的考试成绩改为及格 SC( Sno,Cno ,grade)【其它】查询与“数据结构”在同一学期开设的课程的课程名和开学...
  • SQL查询语句基础

    千次阅读 2021-07-18 05:19:24
    1.查询全体学生的学号与姓名select sno,snamefrom student;3.查询全体学生的详细信息select *from student;4.查询全体学生的姓名及其出生年份select sname,2004-sagefrom student;5.查询全体学生的姓名,出生年份和...
  • SQL查询语句中,什么叫子查询

    千次阅读 2021-03-04 05:57:32
    展开全部嵌套SELECT语句也叫子查询,一个 SELECT 语句的查询结果能够作为另一个语句的输入值。子查询不但能够出现在Where子句32313133353236313431303231363533e59b9ee7ad9431333365633865中,也能够出现在from子句...
  • 查询选修了全部课程的学生姓名【转】

    万次阅读 多人点赞 2019-07-31 22:42:30
    理解如下: 查询选修了全部课程的学生姓名。  不用管怎么样,第一个select 必定是在 student 表里选 sname 既:  SELECT Sname  FROM Student 加上条件即: where 条件是什么呢? 条件就是: 查询选修了全部...
  • 版权所属:SO JSON在线解析 ...  JPA 的查询有很多丰富的API,基本能满足了所有的基本查询...根据方法名字生成SQL语句(根据方法名查询)。 public interface UserRepository extends Repository&lt;User, Lon...
  • SQL结构化查询语言

    千次阅读 2019-06-25 13:04:38
    SQL(structured query language),中文意思是结构化查询语言,它是一种对关系型数据库中的数据进行定义和操作的语言方法,是大多数关系型数据库管理系统所支持的语言。 二、SQL的分类 SQL结构化查询语言分为6个...
  • SQL数据库的组合查询和统计查询

    千次阅读 2020-09-02 09:33:07
    数据库的组合查询和统计查询 一、实验目的 对数据库进行组合查询和统计查询 二、实验内容 1、加深对SQL语言查询语句的理解 2、熟练掌握数据查询中的分组统计、计算和组合操作方法。 三、实验要求 在本题下面提交基本...
  • MySQL(4)— 数据查询

    千次阅读 2021-02-08 14:24:59
    四、数据查询(DQL)4-1、查询指定字段select 完整 语法:select [distinct] 字段名1 [as] [别名],字段名2 [as] [别名]from 表1[ left | right | inner join 表2] on 两表有关联的连接点 -- 连表查询[where ......
  • 左连接查询在开发中很常用,但有个问题常常会遇到,两个表中有同名字段时,比如左右表都有一个id字段,会造成查询结果中左表的id值被右表的id值覆盖掉(大部分php框架都是这个效果),而且还不会报错,容易留下隐蔽...
  • 简单查询 、按条件查询 、高级查询 、为表和字段取别名
  • select a.DESC0, a.DID, case when b.xusertype ='167' then 'varchar('+convert(varchar(10),b.length)+')' when b.xusertype ='61' then 'datetime' when b.xusertype ='36' then 'GUID' when b.xusertype ='108'
  • 数据库SQL语句中 查询选修了全部课程的学生的学号和姓名查询选修了全部课程的学生姓名。 SELECT Sname FROM Student WHERE NOT EXISTS (SELECT * FROM Course WHERE NOT EXISTS (SELECT * fROM SC WHER...
  • MySQL查询练习2

    千次阅读 2021-01-27 19:17:06
    MySQL查询练习2导读:本次MySQL的查询语句是本人考试题目;所有题目都已通过;...BORROW(借书记录)表 :CNO 借书卡号,BNO 书号,RDATE 还书日期列含义 列名 类型 主键/外键卡号 Cno Int 主键非空,参照car...
  • 根据方法名字生成SQL语句(根据方法名查询)。 public interface UserRepository extends Repository&lt;User, Long&gt; { List&lt;User&gt; findByEmailAddressAndLastname(Strin...
  • 前言 相信大家在平时工作中都有过 SQL 优化经历,那么在优化前就必须找到慢 SQL 方可进行分析。这篇文章就介绍下如何定位...指定慢查询日志文件的路径和名字,可使用绝对路径指定,默认值是主机名-slow.log,位于配置的
  • SQL查询单表数据(一)

    万次阅读 2020-02-17 21:21:48
    在 SQL 中,字符 “*” 具有特殊的含义,使用用它,将从指定的表中返回每一列,在这里由于没有使用 where 子句,所以将会返回每一行,即是 查询表中所有的行与列,就是所有的数据 。 还有一种写法就是分别列出每一列...
  • 查询oracle数据库实例的名字

    千次阅读 2021-04-30 09:23:59
    查询oracle数据库实例的名字dc-test2sqlplus /nologSQL*Plus: Release 10.2.0.4.0 - Production on Thu Feb 25 22:44:25 2010Copyright (c) 1982, 2007, Oracle. All Rights Reserved.SQL> conn / as sysdba...
  • 首先要理解group by 含义:“Group By”从字面意义上理解就是根据“By”指定的规则对数据进行分组,所谓的分组就是将一个“数据集”划分成若干个“小区域”,然后针对若干个“小区域”进行数据处理。 先来看这样一...
  • sql查询实例2(借书卡、图书、借书记录)

    千次阅读 多人点赞 2019-12-08 14:08:25
    CNO 卡号,NAME 姓名,CLASS 班级 BOOKS 图书。 BNO 书号,BNAME 书名,AUTHOR 作者,PRICE 单价,QUANTITY 库存册数 BORROW 借书记录。 CNO 借书卡号,BNO 书号,RDATE 还书日期 备注:限定每人每种书只能借一本...
  • 文章目录SQL语法格式单表查询1.基础查询2.条件查询3.模糊查询4.统计查询5.分组查询 SQL语法格式 SELECT [all | DISTINCT] <目标列表达式> [别名] [,<目标列表达式> [别名]]... FROM <表名或视图名>...
  • 文章目录一、where或having后面1.1 标量子查询1.2 ...子查询含义:     出现在其他语句的select语句,称为子查询或内查询     外部的查询语句,称为主查询或外查询 分类: 按子查询出现的位置: &nb...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 109,505
精华内容 43,802
关键字:

名字的含义查询