根据多列的比较在数据库中创建列

时间:2013-07-10 18:12:06

标签: java sql database

我正在使用Java和SQL来编写我正在编写的数据库程序(使用Oracle数据库)。假设我有一个如下表:

Student         Major

 Student1        CS
 Student1        Math
 Student1        CS
 Student2        English
 Student2        Bio
 Student2        English

我可以举报学生从一个专业转到另一个专业然后回到原专业的最佳方式是什么?理想情况下,输出看起来像:

Student         Major          Flagged_Values

 Student1        CS
 Student1        Math
 Student1        CS                 1 
 Student2        English
 Student2        CS
 Student2        English            1

由于Student1和Student2改变了专业,然后又回到原来的状态。我是数据库编程的新手,我最困惑的部分是根据学生或身份证号码比较多列中的值,例如我上面的例子。如果有人能解释如何做到这一点,那将会有所帮助。

String switches = "SELECT Table.Student, Table.Major, " +
            "COUNT(*)OVER (partition by Major)WHERE(partition by Student)" +
            "AS Switches FROM Table";
    ResultSet result = st.executeQuery(switches);

这是我到目前为止的代码,但我不知道在一个语句中分区两次是否有效,或者我是否需要子分区。如果我想添加一个带有标记值的新列,我是否需要一个while循环来迭代上面的ResultSet?提前谢谢。

2 个答案:

答案 0 :(得分:1)

首先,您需要一个字段来标识这些更改的顺序。否则就没有“先前”的概念。对于下面的示例,我将使用“trans”字段,该字段随着每个学生的更改而递增。

我会使用两个子查询 - 一个用于捕获前一个事务(用于确定此事务是否为主要交换),另一个用于识别当前主要事务是否适用于任何先前的事务。

我这样做了两种方式。第一个只显示符合条件的记录,它显示当前主要和最近的主要:

select
   students.student,
   students.major,
   students.trans,
   prev_row.major prev_major,
   prev_row.trans prev_trans
 from
   students
   join students prev_row
     on (students.student = prev_row.student
       and students.trans = prev_row.trans + 1
       and students.major != prev_row.major)
 where
   exists (select 'x'
             from students prev_row
            where students.student = prev_row.student
                 and students.trans > prev_row.trans + 1
                and students.major = prev_row.major);

联接中的第二个表(“prev_row”)查找学生的前一行(students.trans = prev_row.trans + 1),但前提是主要内容不同(students.major != prev_row.major)。

“where exists”进一步将结果限制为仅包含当前主要记录的先前记录的记录。

使用样本数据:

Student     Maj.    Trans
Student1    CS      1
Student1    Math    2
Student1    CS      3
Student2    English 1
Student2    Math    2
Student2    Math    3
Student2    Math    4
Student2    English 5
Student2    Law     6
Student2    Math    6

这将产生以下结果:

STUDENT     MAJOR   TRANS   PREV_MAJOR  PREV_TRANS
Student1    CS      3       Math            2
Student2    English 5       Math            4
Student2    Math    6       English         5

我使用的第二种方法将显示您想要的结果:

 select
   students.student,
   students.major,
   students.trans,
   case when prev_row.student is not null
             and exists (select 'x'
                           from students prev_row
                          where students.student = prev_row.student
                               and students.trans > prev_row.trans + 1
                               and students.major = prev_row.major)
        then 1 else null end is_back
 from
   students
   left join students prev_row
     on (students.student = prev_row.student
       and students.trans = prev_row.trans + 1
       and students.major != prev_row.major)

这使用相同的逻辑,但是使用内部联接和大小写何时显示所有行,并使用切回标记。

SQLFiddle here

答案 1 :(得分:0)

假设您有一个名为“Key”的自动递增主键字段,我认为您可以使用自联接来获取代表切回的行:

SELECT s1.Key 
FROM [student_table] s1
JOIN [student_table] s2 on s1.Student = s2.Student AND s1.Major = s2.Major
WHERE s1.Key > s2.Key 

验证是否适用于您的数据。然后执行实际更新...这不应该像添加Flagged_Values列然后运行查询一样简单:

UPDATE [student_table] s
SET s.Flagged_Values = 1
WHERE s.Key IN
   (SELECT s1.Key 
    FROM [student_table] s1
    JOIN [student_table] s2 on s1.Student = s2.Student AND s1.Major = s2.Major
    WHERE s1.Key > s2.Key)