【问题标题】:When to use an identifier in SQL queries何时在 SQL 查询中使用标识符
【发布时间】:2011-08-18 01:35:19
【问题描述】:

我刚刚查看了一些示例数据库查询,发现了这个:

查找研究部门员工的标识符、姓名和地址。

方法一:加入方法

SELECT Ssn, FName, LName, Address
FROM EMPLOYEE, DEPARTMENT
WHERE Dno = Dnumber
AND Dname = ‘Research’

方法二:子查询法

SELECT Ssn, FName, LName, Address
FROM EMPLOYEE
WHERE Dno IN
( SELECT Dnumber
FROM DEPARTMENT
WHERE Dname = ‘Research’ );

在这些示例中,为什么不能省略 Dno = Dnumber 行?你怎么知道什么时候包含这个?

【问题讨论】:

  • @John,你从哪里得到那些难看的花引号?
  • @Johan,这种语法 SELECT Ssn, FName, LName, Address FROM EMPLOYEE, DEPARTMENT WHERE Dno = Dnumber 自 SQL'89 以来已被贬低,使用显式连接语法 cf ansi '92 会好得多。见wikipedia:join
  • 不,这不是家庭作业...引号在我的笔记中! :)
  • @John,可以在 SO 上做功课。有些人介意有些人不介意。而且我知道那个例子来自教科书。
  • @Johan 正确回答问题很重要......如果问题正在寻找“学术”答案,我们可能会采用与“现实世界”解决方案不同的方法。

标签: mysql sql select key


【解决方案1】:

约翰,您正在使用隐式连接语法 cf ansi SQL '89。

在哪里加入

SELECT Ssn, FName, LName, Address
FROM EMPLOYEE, DEPARTMENT
WHERE Dno = Dnumber
AND Dname = 'Research'

您应该永远不要使用它,因为它会令人困惑。
它会导致很多错误,因为如果你不小心它会执行cross join
以下语法使用显式连接 cf ANSI SQL '92 更加清晰。

SELECT Ssn, FName, LName, Address
FROM EMPLOYEE
inner join DEPARTMENT on (employee.dnumber = department.dno)
WHERE Dname = 'Research'

这也回答了为什么你不能省略dnumber = dno因为那是连接条件

子查询
子查询实际上是通过其他方式进行的连接。
一般来说,您应该避免使用子查询,因为连接更快(90% 的时间)

有些人发现子查询更容易理解。我会说,如果你不 grok joins 远离 SQL!
有时您仍然会为连接做一些复杂或奇怪的事情,然后子查询是一种选择。

回到您的问题:因为子查询实际上是通过其他方式进行的连接,您需要该连接条件来进行连接:-)。

【讨论】:

  • 如果您查看this question 中链接的试卷,您会注意到您坚持认为他“永远不应该使用”的样式与试卷中使用的样式完全相同。如果是我参加这次考试并且我想最大化我的分数(而不是像往常一样成为一个聪明的 alec :) 我会采用相同的风格。
  • @onedaywhen,它在 1992 年被 ANSI 礼让正式贬值!这个考试礼遇沉睡了多久?我并不奇怪大学会落后于时代。我记得在一个软件公司的情况下进行审计考试,官方的重点是首席安全官应该保护软件的“母带”。这当然很愚蠢,因为在软件中所有副本都是相同的。
  • “它在 1992 年被 ANSI [委员会] 正式贬值”——如果是这样,它就没有达到 ISO 标准。有问题的连接样式符合 SQL-92、SQL-99 和 SQL:2003。我宁愿认为您将风格和时尚与 ANSI/ISO 标准混淆了。
  • ...您可以使用Mimer SQL-92 online validator 自己测试它。
  • @onedaywhen,它在 ANSI '89 中,并且为了向后兼容而保留。但是很抱歉,它没有贬值,它仍然是非常糟糕的形式,容易出错和令人困惑。 (意外的完全外部连接等)。
【解决方案2】:

我实际上会写这样的东西。

SELECT 
   Ssn, FName, LName, Address
FROM 
   EMPLOYEE
LEFT JOIN 
   DEPARTMENT ON EMPLOYEE.Dno = DEPARTMENT.Dnumber
WHERE 
   Dname = "Research"

【讨论】:

  • 那不会打印所有员工,这不是我们想要的吗?为什么这更可取?我不是说这不是更好,只是好奇!
  • 你可以试试看..它应该打印“研究部门”的所有员工,如果我猜对了你的数据库结构。
【解决方案3】:

Dno = Dnumber 用于桥接EmployeeDepartment 表之间的JOIN。您需要它来识别要加入的表之间的关系。

JOIN 语句的编写方式有很多种。

这是一个关于连接的好教程 - http://mysqljoin.com/

【讨论】:

    【解决方案4】:

    每个员工都属于一个部门。 Dno = Dnumber 定义了两者之间的关系。所以你必须在你的加入中保持这种关系。 Dname = 'Research' 进一步过滤以仅包括研究部门的员工。

    如果您不将 Dno 加入 Dnumber,您将得到笛卡尔积。

    【讨论】:

      【解决方案5】:

      “Dno = Dnumber”行是连接子句 - 它告诉查询只包含雇员表中 Dno 与部门表中的部门号匹配的记录。

      【讨论】:

        【解决方案6】:

        您使用Dno = Dnumber 行来创建JOIN 标准。

        如果您不使用它们,您将拥有完整的 JOIN 但是,我认为执行JOIN正确 方法是实际执行

        SELECT 
            EMPLOYEE.[Ssn]
            , EMPLOYEE.[FName]
            , EMPLOYEE.[LName]
            , EMPLOYEE.[Address]
        FROM 
            EMPLOYEE
        JOIN 
            DEPARTMENT 
                ON DEPARTMENT.[Dnumber] = EMPLOYEE.[Dno]    
        WHERE 
            DEPARTMENT.[Dname] = 'Research'
        

        【讨论】:

          【解决方案7】:

          连接两个表需要 Dno = Dnumber 子句。没有这个,您将获得所谓的笛卡尔连接,您将获得 n x m 返回的行数,其中 n = EMPLOYEE 表中的 # 行,m = DEPARTMENT 表中的 # 行。

          您可以在http://www.1keydata.com/sql/sqljoins.html 找到一个很好的 SQL 连接教程。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-11-16
            • 2020-05-16
            • 2015-03-29
            • 1970-01-01
            • 1970-01-01
            • 2014-09-26
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多