#java #oracle #jdbc
Вопрос:
Я пытаюсь создать контактную программу, в которой каждый человек указан со своими электронными письмами. Как вы знаете, у каждого человека может быть несколько электронных писем. Так, например, у Джона Смита есть 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 запись со списком всех писем с разделителем, или, если в данном случае это не лучшая практика, вы можете сказать мне по-другому.
Комментарии:
1. Вы должны решить эту проблему, добавив соответствующие ограничения в таблицу в своей базе данных, чтобы предотвратить существование повторяющихся записей. Если это не то, что вы имеете в виду, то, пожалуйста, будьте более откровенны в том, какую проблему вы пытаетесь решить и какого результата вы ожидаете.
2. Они не являются дубликатами. У пользователя 1 есть три адреса электронной почты. Какой из них ты хочешь?
3. Правильное название должно быть: «Как предотвратить получение 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
Я не думаю, что применение UNIQUE
ограничений к PERSON_EMAILS
таблице-хороший вариант. Черт возьми, большинство из нас использует несколько адресов электронной почты (на работе, личные, еще один частный, …), и Джон Смит тоже.
Есть и другие варианты, но вы должны сказать, чего вы действительно хотите.
Комментарии:
1. так что да, пример с LISTAGG великолепен — это именно то, что я хочу отобразить в своем Java-приложении. Является ли это лучшей практикой — например: если у меня есть еще одна таблица в базе данных, называемая — номера телефонов, и я хочу перечислить электронные письма и номера телефонов этого человека, должен ли я продолжать использовать LISTAGG?
2. Я верю в это. Это просто зависит от того, какой формат вы хотите; я думаю, что два столбца (один для списка адресов электронной почты кого-то, а другой для их телефонных номеров) — самый простой вариант. В противном случае вы могли бы объединить два результата LISTAGG в один столбец. Или вы даже можете «смешать» адреса электронной почты с номерами телефонов …
3. @NewJavaEnthusiast Если вы согласны с тем, что LISTAGG не существует во многих базах данных, тогда действуйте. В противном случае простым методом было бы выполнить два запроса.
4. @Страшно, тег Oracle предполагает, что это Oracle, так что я думаю, что в конце концов все в порядке.
5. @ScaryWombat так что в моем случае база данных наверняка будет Oracle. Два запроса, безусловно, более чистый способ (для меня), но представьте, что я хочу расширить проект, добавив — person_address, person_university и т. Д. Таким образом, я думаю, что будет много запросов к базе данных, которых я надеюсь избежать.