1

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

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?提前致谢。

4

2 回答 2

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

“在哪里存在”进一步将结果限制为仅在当前专业中存在先前记录的那些记录。

使用样本数据:

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)

这使用了相同的逻辑,但使用了内部连接和 case when 显示所有行,并使用 switch-back 标记这些行。

SQLFiddle在这里

于 2013-07-10T19:48:16.190 回答
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)
于 2013-07-10T19:43:38.253 回答