如何使用 Java 和 JDBC 防止一对多关系中的重复?

Posted

技术标签:

【中文标题】如何使用 Java 和 JDBC 防止一对多关系中的重复?【英文标题】:How to prevent duplicates in one to many relation using Java and JDBC? 【发布时间】:2021-08-18 07:18:16 【问题描述】:

我正在尝试制作一个联系程序,其中每个人都与他们的电子邮件一起列出。如您所知,每个人都可以拥有多封电子邮件。例如,John Smith 有 3 封电子邮件。

public class OneToManyDB 
   static final String DB_URL = "jdbc:oracle:thin:@1.1.1.1:1521:orcl";
   static final String USER = "user";
   static final String PASS = "pass";
   static final String QUERY = "select prs.person_id, prs.first_name, prs.last_name, pe.email" +
           " from persons prs" +
           " left join person_emails pe on prs.person_id = pe.person_fk" +
           " where prs.person_id = 1";

   public static void main(String[] args) throws SQLException 
      
        Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
        if (conn != null) 
            try 
                Statement stmt = conn.createStatement();
                ResultSet rs = stmt.executeQuery(QUERY);
                      
                while(rs.next())
                   System.out.print("ID: " + rs.getInt("person_id"));
                   System.out.print(", First: " + rs.getString("first_name"));
                   System.out.print(", Last: " + rs.getString("last_name"));
                   System.out.println(", Email: " + rs.getString("email"));
                
             catch (SQLException e) 
                e.printStackTrace();       
            
        
    
      

您可以看到此人的名字和姓氏以及他/她的电子邮件联系人。 您还可以看到列出它们的问题。输出是:

如何避免这种重复?我无法在任何地方找到纯 Java 解决方案,因为我无法使用 Hibernate。请帮忙!

我想要得到的输出是 1 条记录,其中列出了所有带有分隔符的电子邮件,或者如果在这种情况下这不是最佳做法,您可以告诉我另一种方式。

附:以下是 person_emails 表中的数据:

【问题讨论】:

您应该通过在数据库中的表上添加适当的约束来解决此问题,以防止存在重复记录。如果这不是您的意思,那么请更明确地说明您要解决的问题以及您期望的结果。 它们不是重复的。用户 1 有三个电子邮件地址。你要哪一个? 正确的标题应该是:“如何防止在一对多关系中获取 N 条记录?” 【参考方案1】:

嗯,它们并不完全是重复的——它们的电子邮件地址不同。所以问题是:在这种情况下你想返回什么?

例如,您可以选择返回任何电子邮件地址;使用聚合函数会有所帮助,因此您可以将查询修改为例如

  SELECT prs.person_id,
         prs.first_name,
         prs.last_name,
         MAX (pe.email) email                           --> this
    FROM persons prs LEFT JOIN person_emails pe ON prs.person_id = pe.person_fk
   WHERE prs.person_id = 1
GROUP BY prs.person_id, prs.first_name, prs.last_name   --> this

或者,您可能想要返回所有他们的电子邮件地址;使用LISTAGG 来做到这一点:

  SELECT prs.person_id,
         prs.first_name,
         prs.last_name,
         LISTAGG (pe.email, ';') WITHIN GROUP (ORDER BY NULL) email  --> this
    FROM persons prs LEFT JOIN person_emails pe ON prs.person_id = pe.person_fk
   WHERE prs.person_id = 1
GROUP BY prs.person_id, prs.first_name, prs.last_name                --> this

我认为在PERSON_EMAILS 表上应用UNIQUE 约束不是一个好的选择。哎呀,我们大多数人都使用多个电子邮件地址(在工作中,私人,另一个私人,......),约翰史密斯也是如此。


还有其他选择,但你必须说出你真正想要的。

【讨论】:

所以是的,带有 LISTAGG 的示例很棒——这正是我想要在我的 Java 应用程序中显示的内容。这是最佳实践吗?例如:如果我在 DB 中有一个名为 -phone_numbers 的表,并且我想列出此人的电子邮件电话号码,我应该继续使用 LISTAGG 吗? 我相信是的。这仅取决于您想要哪种格式;我猜两列(一列是某人的电子邮件地址,另一列是他们的电话号码)是最简单的选择。否则,您可以将两个 LISTAGG 结果连接到一个列中。或者,您甚至可以将电子邮件地址与电话号码“混合”... @NewJavaEnthusiast 如果您接受 LISTAGG 在许多数据库中不存在,那么就去吧。否则,一个简单的方法就是执行两个查询。 @Scary, Oracle 标签提示它is Oracle,所以我想还是可以的。 @ScaryWombat 所以在我的情况下,数据库肯定是 Oracle。两个查询当然是更清洁的方式(对我来说),但想象一下我想通过添加 - person_address、person_univercity 等来扩展项目。这样我认为这将是对数据库的很多请求,我希望避免。

以上是关于如何使用 Java 和 JDBC 防止一对多关系中的重复?的主要内容,如果未能解决你的问题,请参考以下文章

mybatis如何实现一对多关联关系

Spring JDBC中的多个一对多关系

使用 JDBC 在一对多中获取“多”

java中如何在map中实现一对多的关系?

如何用jdbc实现一对多

Java 中mybatis 关系映射,比如:一对多