【问题标题】:Exclude column from natural join从自然连接中排除列
【发布时间】:2018-04-05 09:48:05
【问题描述】:

我目前有以下 PostgreSQL 数据库(图片仅包含基本组件):

基本上: 每个 TX 有一定数量的 TXIN 和一定数量的 TXOUT,每个 TXIN 由一个 TXOUT 环(门罗币交易)组成

如果我将ring 表与txin 表连接起来,我使用select * from ring natural join txin,它使用inid 进行连接。 ringtxout 相同,但它加入 outid

txintxout 也可以通过自然连接 tx 进行连接以获得合理的输出。

唯一(预期)不起作用的是:

select * from txout natural join ring natural join txin;

因为它随后加入了ring(inid) = txin(inid)ring(outid) = txout(outid)(这是需要的),但也加入了不希望的txin(txid) = txout(txid)

我对如何解决这个问题有一些想法:

  1. 使用显式连接(在我看来使某些查询非常麻烦),例如以上将是:select * from txout join ring using (outid) join txin using (inid);

  2. 重命名 txin 或 txout 中的两个 txid 列之一,并放弃与 tx 的自然连接

  3. 为这些操作使用省略 txid 的 txin/txout 视图

还有其他(更好的)方法吗?如果不是 - 哪种方法是最佳实践? 我的数据库设计是否缺乏,整个问题可以通过某种方式规避?

【问题讨论】:

  • 帮自己一个忙,忘记natural join 构造。指定连接列!
  • 这是自然连接的不良副作用,当您的表中有一些 DATE 列时可能会发生很多情况。我永远不会使用它...
  • @dnoeth 这个想法是您的数据元素名称应该在整个架构中保持一致和唯一,而不是依赖表名来提供上下文。至于您给出的示例,我已经看到设计人员在同一个表中混合了审计数据(例如行创建日期)和“实体”数据,而不是有单独的审计表。将这些修复应用于损坏的架构,NATURAL JOIN 更易于使用。

标签: sql postgresql join natural-join


【解决方案1】:

自然连接被明确定义为连接具有相同名称的所有列。就是这样,它实际上与(如果此语法有效)JOIN table USING (*) 相同。 冗长的 SQL 没有任何问题。非常清楚您的连接条件会更好且更易于维护,这意味着如果您将来在这些表中添加一列,它就不会与历史数据混淆。在这种情况下,我建议使用显式语法加入,因为这样可以清楚数据的来源:

SELECT * 
FROM txout to
INNER JOIN ring r ON (to.outid = r.outid)
INNER JOIN txin ti ON (r.inid = ti.inid)

这里要清楚。自然连接不是一个可维护的解决方案,它们非常适合在紧要关头将视图组合在一起,但架构会发生变化,如果您使用自然连接而不是显式连接,那么当它们这样做时会遇到问题。

我不太确定您为什么要按照自己的方式设计数据库,看起来数据有意重叠并且可以全部放在 (txid, inid, outid, txhash) 的单个表中,但也许我缺乏完整的上下文。

【讨论】:

  • 如果你想节省一些打字,另一种选择是... join ring r using (outid)
  • 我本来打算这么说的,但我想对于第一次来这里的人来说,声明你加入 ring 是为了 outids,然后从 ring 你加入inids 上的 txin 更清晰(当然,熟悉架构的人都知道这一点,而且两者在性能方面几乎可以忽略不计)
  • 谢谢。我会和这个一起去的。关于单表设计: TX 可以有多个输入和多个输出,每个输入也可以有多个输出。我想如果我使用单表方法,我将不得不多次保存 txhash(对于 inid 和 outid 的每个组合)而不是只保存一次。
  • “模式改变了,如果你使用自然连接而不是显式连接,你会遇到问题”——只有在你没有正确完成工作并且编码失败的情况下防守!例如仅通过这些视图/过程为这组用户提供对这些表的访问,然后测试对表的更改不会破坏这些客户端。
  • “冗长的 SQL 并没有什么问题。它更好,更易于维护”——观点呈现为事实!您能多快通过肉眼验证这两者是否相关?:SELECT C1, C4, C8, C7, C5, C0, C6, C2, C9, C3 FROM T;SELECT C6, C1, C9, C4, C8, C3, C0, C2, C5, C7 FROM T;。你能多快用肉眼验证这两者是否相关?:SELECT * FROM T; vs SELECT * FROM T;
【解决方案2】:

我会推荐简化的 Oracle 语法:

SELECT * 
  FROM ring
  JOIN txout USING(outid)
  JOIN txin  USING(inid)

【讨论】:

    猜你喜欢
    • 2015-02-09
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 2016-07-10
    • 2013-04-13
    • 1970-01-01
    • 2012-09-28
    相关资源
    最近更新 更多