【问题标题】:basic many-to-many sql select query基本的多对多 sql 选择查询
【发布时间】:2009-01-23 16:44:32
【问题描述】:

我认为这应该很容易,但它在逃避我。我在帐户和帐户组之间建立了多对多的关系。一个帐户可以在零个或多个组中,因此我使用的是标准连接表。

Accounts 
--------
ID
BankName
AcctNumber
Balance

AccountGroups
-------------
ID
GroupName

JoinAccountsGroups
------------------
AID
GID

我正在使用 MS Access,FWIW。此外,这适用于低带宽情况,因此代码优化不如简单/可读性重要。

我使用 php 作为表示层,所以 Access 的基本结果很好。

至于如何处理多结果情况,我实际上有两件事我正在尝试构建。第一个在一个列中列出所有组:

Bank       AcctNum       Balance    Groups
--------|--------------|----------|----------------
Citi       930938        400        Payroll
HSBC       8372933       100        Monthly, Payroll
Wells      09837         800        -
Chase      8730923       250        Monthly

第二个是主从列表:

Name          AcctNum    Balance
------------|----------|----------
Payroll (2)              500
  Citi        930938     400
  HSBC        8372933    100         
..................................
Monthly (2)              350
  HSBC        8372933    100         
  Chase       8730923    250
..................................
Wells         09837      800

对于主从细节,我的计划只是从数据库中获取一个大的结果集,并根据需要在 php 中调整它。由于无论如何都会在 php 中进行一些重要的后处理,也许我应该只做三个单独的查询并在那里进行连接。 (因为我更喜欢那种语言。)

【问题讨论】:

  • 您的数据令人困惑,因为您有一个多对多的加入,当有 2 个以上的组与一个帐户关联时,您会发生什么?您的输出显示每个帐户一行??
  • 您使用的不是 Access,而是使用 Jet MDB 作为数据存储。
  • “你没有使用 Access”:你怎么知道他们没有使用 MS Access 来编写 Jet 语法 SQL(你也这样做)?您怎么知道他们没有使用 Access 2007 的 ACE,其中“A”代表“Access”?

标签: sql ms-access many-to-many


【解决方案1】:

这个

SELECT a.BankName, a.AcctNumber, a.Balance, ag.GroupName
FROM (Accounts a 
      LEFT JOIN JoinAccountsGroups jag 
      ON a.ID = jag.AID) 
      LEFT JOIN AccountGroups ag
      ON jag.GID = ag.GroupName;

将为第一个表选择数据,但是要连接组(每月、工资单),您需要一个用户定义函数 (UDF),Jet 无法使用该函数,因此需要在 PHP 中进行处理。

您不妨阅读Understanding SQL Joins。它指的是 MySQL,但在大多数情况下适用于 Jet。

【讨论】:

    【解决方案2】:

    另一个想法...为什么不在 Access 中使用查询设计器。设计“视图”大约需要 30 秒。那你去看看它写的SQL。

    【讨论】:

    • 因为我真的不知道如何使用它,所以我的短暂尝试失败了。 :)
    • 查询设计器非常有用,但不会为此查询设置正确的连接,您需要知道连接类型。查询设计窗口还会为更复杂的查询生成错误的 sql。
    【解决方案3】:

    SQL Server 为此目的使用 ISNULL()。我不确定这是否适用于 Access。

    【讨论】:

    • Nz()(即“null to zero”,虽然第二个参数可以是任何数据类型)。
    • 糟糕。是的,正如 Anothony Jones 在下面指出的那样,Nz() 不能通过 ODBC 或 OLEDB 使用,只能在 Access 中使用。
    • 是的,很容易将 Access 的功能与 Jet 的功能混淆,不是吗? :)
    【解决方案4】:
    SELECT act.acctid AS AcctId, bankName, acctNumber, Balance, 
           NVL(jag.gid, '-') AS GroupID, NVL(gp.groupname, '-') AS GroupName
    FROM accounts act 
         LEFT OUTER JOIN JointAccountGroups jag ON (act.id = jag.aid) 
         LEFT OUTER JOIN AccounGroups gp ON (jag.gid = gp.id)
    

    NVL 是一个函数,意思是“如果第一个参数为空,则返回第二个参数;否则,返回第一个参数”。 NVL 恰好是 Oracle 的做法——所有数据库都有类似的东西,但它没有标准名称;查看 Access 是如何做到的。

    【讨论】:

    • 或者只是将null保留在原处,并在表示层中将其显示为'-'。
    • 自然 :-)。我不知道他是否有 表示层,所以为了完整起见,我将其加入。但是,如果可以实现表示和数据的分离,那么应该,你是对的。
    • NVL 可能类似于 T-SQL 中的 COALESCE,我不是 Oracle 人。
    • 在访问它的 Nz() 但我不确定通过 JET 驱动程序是否可用
    • 不,Jet 无法使用 NZ,请使用 IIF(jag.gid IS NULL, '-', jag.gid)
    【解决方案5】:

    是的,我将使用表示层作为 NULL。

    但我一定错过了什么。我从您那里得到的错误与我最初的尝试相同:

    Syntax error (missing operator) in query expression '(act.id = jag.aid) 
                      LEFT OUTER JOIN accountgroups gp ON (jag.gid = gp.id)'
    

    【讨论】:

    • Access 中的“加入”短语的数量是否存在语法限制?您是否尝试过使用 Where 子句强制连接? (其中act.id=jag.aid)?这只会给你一个内部连接,你必须将结果连接回帐户并获取丢失的..
    • 请编辑您的问题并添加详细信息,不要使用答案添加详细信息。另请注意,您的输出规范仍需要修改。
    • Jet 数据库引擎优化隐式连接(使用 WHERE 子句)与等效的 JOIN 完全相同,因此将显式连接替换为隐式连接没有任何优势。在我使用 Access 的这些年里,我从来没有遇到过任何加入数量的限制。
    • 在 Jet 中,将单行表连接到自身 33 次,您将收到“查询太复杂”错误。 SQL 的字符数只有 K1.5 个字符,结果集只有一行,因此连接数必须是限制因素。
    • 对于 Jet,您必须将每个连接放在括号中,例如(LEFT OUTER JOIN JointAccountGroups jag ON act.id = jag.aid) LEFT OUTER JOIN AccounGroups gp ON jag.gid = gp.id
    【解决方案6】:

    怎么样:

    SELECT act.acctid AS AcctId, bankName, acctNumber, Balance, 
          jag.gid AS GroupID, gp.groupname AS GroupName
    FROM accounts AS act 
         LEFT OUTER JOIN JointAccountGroups AS jag ON act.id = jag.aid
         LEFT OUTER JOIN AccounGroups AS gp ON jag.gid = gp.id
    

    这会给你一个错误吗?也许是更容易发现的错误?

    【讨论】:

    • 这与没有 NVL 的 OR 相同,并且添加了更多的 AS,对吗?这实际上是我投入的......
    【解决方案7】:

    我认为在 Access 中您可能想尝试以下操作:

    FROM (accounts AS act 
         LEFT OUTER JOIN JointAccountGroups AS jag ON act.id = jag.aid)
         LEFT OUTER JOIN AccounGroups AS gp ON jag.gid = gp.id
    

    我不知道为什么括号很重要,但我尝试了一个测试,它似乎解决了它。

    【讨论】:

      【解决方案8】:

      再试一次:

      SELECT act.acctid AS AcctId, bankName, acctNumber, Balance, 
          jag.gid AS GroupID, gp.groupname AS GroupName
      FROM accounts AS act 
         LEFT OUTER JOIN JointAccountGroups AS jag ON act.id = jag.aid
         LEFT INNER JOIN AccounGroups AS gp ON jag.gid = gp.id
      

      两个 OUTER JOIN 的访问可能有问题,所以我将第二个设置为 INNER JOIN,它应该可以工作

      【讨论】:

        【解决方案9】:

        不仅使用前面建议的查询设计器,还使用MS Access关系工具记录两个外键(AID、GID)和它们引用的主键之间的关系。

        这使得在查询设计器中进行自然连接几乎是小菜一碟。您甚至可以在您概述的情况下使用查询向导。

        一旦构建了查询,为什么不使用查询作为记录源而不是使用表?

        我会在 PHP 中做的一件事是将多个结果转换为逗号分隔的列表。

        【讨论】:

          猜你喜欢
          • 2017-11-17
          • 1970-01-01
          • 2015-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-08
          • 1970-01-01
          • 2011-03-30
          相关资源
          最近更新 更多