使用 JDBC 在一对多中获取“多”
Posted
技术标签:
【中文标题】使用 JDBC 在一对多中获取“多”【英文标题】:Getting the "many" in one-to-many using JDBC 【发布时间】:2021-01-08 03:20:14 【问题描述】:我现在有两个表,它们形成一对多的关系。一张餐桌,映射到多次检查。我的 postgres 表是这样定义的:
CREATE TABLE restaurant (
id UUID NOT NULL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
zip VARCHAR(255),
address VARCHAR(255),
phone VARCHAR(255)
);
CREATE TABLE inspection (
restaurant_id UUID NOT NULL,
date VARCHAR(255) NOT NULL,
score int,
violation VARCHAR(255),
risk VARCHAR(255),
FOREIGN KEY (restaurant_id) REFERENCES restaurant(id)
);
当我查询一家餐厅时,我不确定如何推断所有检查。我正在使用resultSet.getString("fieldName")
获取餐厅的所有字段,但是当我尝试resultSet.getString("inspection")
时它不起作用。我需要什么代码来进行这些检查?这是我目前获取所有餐馆的查询。
@Override
public Optional<Restaurant> selectRestaurantById(UUID id)
final String sql = "SELECT * FROM restaurant WHERE id = ?";
List<Restaurant> res = jdbcTemplate.query(
sql,
new Object[] id,
(resultSet, i) ->
UUID restaurant_id = UUID.fromString(resultSet.getString("id"));
String name = resultSet.getString("name");
String zip = resultSet.getString("zip");
String address = resultSet.getString("address");
String phone = resultSet.getString("phone");
// How do I get an ArrayList of inspections from postgres??
Restaurant r = new Restaurant(restaurant_id, name, zip, address, phone);
return r;
);
Restaurant found = res.size() > 0 ? res.get(0) : null;
return Optional.ofNullable(found);
【问题讨论】:
您应该加入表格以获取所有详细信息 - SELECT * FROM restaurant r INNER JOIN INSPECTION i on r.id = i。 restaurant_id WHERE r.id = ?由于餐厅的一对多关系,您将获得重复的餐厅,因此您可以使用连接进行两次查询或首先处理重复。 【参考方案1】:这与 java 或 JDBC 无关。启动一个基本的 sql 终端(如果您在终端上使用 postgres,psql
,那会很好)并首先学习 SQL。幸运的是,网上有很多教程可以找到:)
查询只会生成另一个表,然后您会循环遍历该表。 SELECT * FROM foo
只是.. 给你那张桌子。请注意,只是那张桌子。餐厅的桌子就是这样。餐馆。里面的任何地方都没有检查。 FOREIGN KEY
并不神奇,SQL 并没有真正具有一对多关系的概念。至少,不是这样定义的——它们有连接的概念,它可以让你在你想要的任何东西之间临时定义这种关系。定义中不需要FOREIGN KEY
。
FOREIGN KEY
所做的所有事情都是对 DB 说:您能否为该字段创建索引,并且请使任何事务失败,否则该事务将在该表中写入 'restaurant_id' 字段具有以下值的行与餐厅表中某行的“id”值不匹配。这和CHECK v > 0
一样有趣。只是在提交时运行的检查。就是这样。
SELECT r.*, i.* FROM restaurant r LEFT JOIN inspection i ON i.restaurant_id = r.id WHERE r.id = ?
会这样做 - 可以这么说,这会创建一个新的“表”。包含行中的每一列,以及检查中的每一列。如果一家餐馆有 0 次检查,你会得到 1 行,其中每个 i.
相关字段都是 NULL(因为 LEFT JOIN;如果你写了 INNER JOIN,你根本不会得到那些餐馆)。对于有 10 次检查的餐厅,您将获得 10 行,其中所有 r.
相关字段都重复。
如果这听起来很烦人 - 是的,我可以看到。然后运行第二个查询:SELECT * FROM inspection WHERE restaurant_id = ?
,获取数据,填充您的数组列表。
注意:您的 tabledef 很奇怪。 score
应该有 NOT NULL
限制。
【讨论】:
感谢您的周到回答!我很好奇,如果我将 10 个检查映射到一家餐厅,访问它们并将它们放入列表的最佳方法是什么? 我可以在函数之外有一个列表,只需将它们添加进去,然后设置获取返回的餐厅列表,但是当我想要返回餐厅列表时我不能这样做,每个都有自己的检查清单。 更一般地说,“首先我将表映射到对象,然后我看到我需要的东西”的想法与 SQL 并不完全吻合,这更适合你只是查询你需要的东西。所以,回答“如果我有 10 个检查映射到一家餐厅,访问它们并将它们放入列表的最佳方式是什么?”我必须知道你为什么想要这些数据以及你想用它做什么。 例如,“我将把数据库中的所有数据库中的所有东西放入一个对象中”的模型就是一个糟糕的模型。想象一下,您不仅有检查,还有其他 40 项。那将是一个巨大的物体。相反,您需要什么?如果它是显示您所在地区的违规行为的网页,那么就这样做。SELECT r.name, STRING_AGG(i.violation, ', ') FROM restaurant r INNER JOIN inspection i ON i.restaurant_id = r.id WHERE r.zip IN (?, ?, ?, ?) AND v.score < 6 ORDER BY r.name
.
我正在开发一个后端 API,所以理想情况下,当有餐厅请求进入时,我应该发送所有餐厅的 JSON 以及他们的检查列表跨度>
以上是关于使用 JDBC 在一对多中获取“多”的主要内容,如果未能解决你的问题,请参考以下文章