【问题标题】:Tricky SQL statement over 3 tables超过 3 个表的棘手 SQL 语句
【发布时间】:2009-09-11 20:20:54
【问题描述】:

我有 3 个不同的事务表,它们看起来非常相似,但略有不同。这是因为有 3 种不同的交易类型;根据事务类型,列会发生变化,因此要将它们放入 3NF 我需要将它们放在单独的表中(对吗?)。

举个例子:
t1: 日期、用户、金额

t2: 日期,用户,谁,金额

t3: 日期、用户、内容、金额

现在我需要一个查询,该查询将为同一用户获取每个表中的所有事务,例如

select * from t1,t2,t3 where user='me'; (这当然行不通)。

我正在研究 JOIN 语句,但还没有找到正确的方法来做到这一点。谢谢。

编辑:实际上我需要每个表中的所有列,而不仅仅是相同的列。


编辑#2:是的,当然,拥有 transaction_type 并不会破坏 3NF - 所以也许我的设计完全错误。这是真正发生的事情(这是一种替代货币系统):
- 交易是在用户之间进行的,就像相互信用一样。所以单位在用户之间交换。
- 清单是带入系统的实物;用户为此获得单位。
- 消耗品是消耗的物质;用户必须为此付费。

|------------------------------------------------- --------------------------| |类型 |交易 |清单 |消耗品| |------------------------------------------------- --------------------------| |专栏 |日期 |日期 |日期 | | |债权人(FK用户) |债权人(FK用户) | | | |借方(FK 用户) | |借方(FK 用户) | | |服务(FK服务)| | | | | |资产(FK资产) |资产(FK资产) | | |金额 |金额 |金额 | | | | |价格 | |------------------------------------------------- --------------------------|

(请注意,“金额”的单位不同;这些是对这些金额进行的输入和计算。超出了解释原因的范围,但这些是字段)。
因此问题变为“可以/这应该在一张桌子上还是多张桌子上(就像我现在拥有的那样)?” 我需要前面描述的 SQL 语句来显示运行余额。


(现在应该完全成为一个新问题还是可以编辑?)。

编辑#3:由于编辑#2 实际上将其转换为一个新问题,因此我还决定发布a new question。 (我希望这没问题?)。

【问题讨论】:

    标签: sql mysql join


    【解决方案1】:

    您可以在选择语句中为没有数据的列提供默认值作为常量;

    所以

    SELECT Date, User, Amount, 'NotApplicable' as Who, 'NotApplicable' as What from t1 where user = 'me'
    UNION
    SELECT Date, User, Amount, Who, 'NotApplicable' from t2 where user = 'me'
    UNION
    SELECT Date, User, Amount, 'NotApplicable', What from t3 where user = 'me'
    

    假设 Who 和 What 是字符串类型的列。您也可以使用 Null,但需要某种占位符。

    我认为将您的附加信息放在一个单独的表中并将所有事务保存在一个表中对您来说会更好,除非我错过了一些其他细节。

    【讨论】:

    • NULL 作为列占位符更安全,因为如果存在值,列输出必须是相同的数据类型。
    • 我应用了这种方法,到目前为止它有效。现在我正在尝试创建一个带有 transaction_type 的“主”事务表,它指的是 3 个单独表中的附加信息。我对此表示怀疑,但是是否可以通过根据 transaction_type 设置外键并因此指向 3 个表之一来获得引用完整性?
    【解决方案2】:

    我认为你的问题的核心在这里:

    根据事务类型,列会发生变化,因此要将它们放入 3NF,我需要将它们放在单独的表中(对吗?)。

    我不是 3NF 专家,但我会以不同的方式处理您的架构(这可能会稍微清除您的 SQL)。

    您的数据元素看起来像这样:dateuseramountwho什么。考虑到这一点,更规范化的模式可能如下所示:

    用户 ---- id,用户信息(用户名等) 谁 --- id,谁信息 什么 ---- id,什么信息 交易 ------------ id、日期、金额、user_id、who_id、what_id

    您的外键约束措辞将根据数据库实现而有所不同,但这更清晰(并且可扩展)。

    【讨论】:

      【解决方案3】:

      您应该考虑 STI“架构”(单表继承)。 IE。将所有不同的列放在一个表中,并将它们全部放在一个索引下。

      此外,您可能希望将索引添加到您正在选择的其他列。

      【讨论】:

        【解决方案4】:

        结果架构会是什么样子? - 如果您只想要所有 3 个表中的最少列,那么很容易,您只需 UNION 结果:

        SELECT Date, User, Amount from t1 where user = 'me'
        UNION
        SELECT Date, User, Amount from t2 where user = 'me'
        UNION
        SELECT Date, User, Amount from t3 where user = 'me'
        

        【讨论】:

        • 尽管考虑 UNION ALL
        • 是的,没有 ALL 的 UNION 可能是 SQL 拥有的最昂贵的语句。
        【解决方案5】:

        或者你可以对它们进行“子类化”

          Create Table Transaction
          ( 
             TransactionId Integer Primary Key Not Null,
             TransactionDateTime dateTime Not Null,
             TransactionType Integer Not Null, 
             -- Othe columns all transactions Share
          )
        
          Create Table Type1Transactions
          {
             TransactionId Integer PrimaryKey Not Null,
             // Type 1 specific columns
          }
          ALTER TABLE Type1Transactions  WITH CHECK ADD  CONSTRAINT 
           [FK_Type1Transaction_Transaction] FOREIGN KEY([TransactionId])
            REFERENCES [Transaction] ([TransactionId])
        

        对其他类型的交易重复...

        【讨论】:

          【解决方案6】:

          简单地将不必要的列保留为空并添加 TransactionType 列怎么样?这将产生一个简单的 SELECT 语句。

          【讨论】:

            【解决方案7】:
            select *
            from (
                select user from t1
                union
                select user from t2
                union
                select user from t3
            ) u
            left outer join t1 on u.user=t1.user
            left outer join t2 on u.user=t2.user
            left outer join t3 on u.user=t3.user
            

            【讨论】:

              猜你喜欢
              • 2010-11-16
              • 2023-03-14
              • 2012-11-24
              • 2015-11-16
              • 1970-01-01
              • 2011-03-13
              • 1970-01-01
              • 2012-03-15
              • 2018-07-04
              相关资源
              最近更新 更多