不符合的 SQL 语法 [已关闭]

non-conforming SQL syntax [closed]

提问人:dougp 提问时间:11/16/2023 最后编辑:dougp 更新时间:11/20/2023 访问量:75

问:


想改进这个问题吗?更新问题,使其仅通过编辑这篇文章来关注一个问题。

4天前关闭。

我正在使用供应商软件,该软件使我能够根据其现代 Oracle 数据库 (18c) 中的数据创建报告。其中一个报告在返回大量数据时遇到问题。供应商通知我,我的 SQL 是“不合格的”。他们说像这样的 SQL......

select a.Name
, a.Descr

from tblA a
  inner join tblB b on b.aID = a.aID
  inner join tblC c on c.bID = b.bID

where sysdate between c.StartDate and c.EndDate
  and c.Name in ('X', 'Y', 'Z')

...错了,而这......

select a.Name
, a.Descr

from tblA a
, tblB b

where b.aID = a.aID
  and b.bID in (
    select c.bID
    from tblC c
    where sysdate between c.StartDate and c.EndDate
      and c.Name in ('X', 'Y', 'Z')
  )

...是正确的。

这是一个戏剧性的例子。原始查询很大,但这基本上是我被告知导致问题的差异。

我很困惑,因为我没有看到任何有意义的区别。

  1. 这些查询是否会产生不同的结果?
  2. “in (subquery)”语法可以避免重复吗?INNER JOIN
  3. 使用子查询如何增加任何值?会更快吗?
  4. 大约 2 年前,“逗号”样式的连接不是被弃用了吗?
SQL 预言机

评论

0赞 Stu 11/16/2023
逗号连接已超过 30+ 年,不应使用。您的查询在技术上很好,但不知道来自哪个表 - 始终限定列。至于它能不能更快,产生不同的结果......你可以测试它,我们不能。sysdate
1赞 Thorsten Kettner 11/16/2023
@Stu:是返回当前日期时间的 Oracle 函数。SYSDATE
0赞 Stu 11/16/2023
哈哈,也许你能发现我不熟悉 Oracle :)
0赞 Eric 11/16/2023
@Stu就像在SYSDATEGETDATE()SQL Server
0赞 jarlh 11/16/2023
我的标准答案:始终使用现代、明确的语法!更易于编写(无错误),更易于阅读和维护,并且在需要时更容易转换为外部连接JOIN

答:

4赞 Thorsten Kettner 11/16/2023 #1

首先,我想这是一个错别字,应该是.b.aID = b.aIDb.aID = a.aID

然后,看到他们希望你使用逗号连接()是很奇怪的,就像在1980年代所做的那样。这是一个过时的语法,现在不应该使用。from tblA a, tblB b

但是,是的,原始查询可能会导致重复的结果行。如果只想从 tblA 中选择数据,则仅从 tblA 中选择并将条件放在子句中。我想这就是他们通过将 tblC 放入子句中来尝试做的事情。一个好主意,它应该看起来像这样:WHEREIN

SELECT a.name, a.descr
FROM tbla a
WHERE a.aid IN 
(
  SELECT b.aid
  FROM tblb b 
  INNER JOIN tblc c ON c.bid = b.bid
  WHERE SYSDATE BETWEEN c.startdate AND c.enddate
  AND c.name IN ('X', 'Y', 'Z')
);

回答您的问题:

  1. 这些查询是否会产生不同的结果?是的。
  2. INNER JOIN是否会导致“in (subquery)”语法避免的重复?是的。
  3. 使用子查询如何增加任何值?会更快吗?是的,速度更快,而且不会产生重复项。
  4. 大约 2 年前,“逗号”样式的连接不是被弃用了吗?实际上,即使在三十年前,甲骨文也晚了十年才采用这种语法。所以,是的。

生产线

WHERE SYSDATE BETWEEN c.startdate AND c.enddate

顺便说一句,看起来有点可疑。startdate 和 enddate 可能是日期,同时还包含时间。因此,我们希望 SYSDATE 在日期范围内,但根据 enddate 是包含还是排除,这应该是SYSDATE

WHERE c.startdate <= SYSDATE AND c.enddate > SYSDATE

WHERE c.startdate <= SYSDATE AND c.enddate > SYSDATE - INTERVAL '1' DAY

为了不让接下来的午夜被包括在内。

评论

0赞 dougp 11/20/2023
感谢您发现错别字。我在两个查询中都修复了它。
0赞 dougp 11/20/2023
谢谢。我将查看生成投诉的条件下的查询输出,看看重复是否可能是问题所在。
1赞 Paul W 11/16/2023 #2

我认为也许供应商并没有试图让 Oracle 原生与 ANSI 连接语法成为问题。我认为他们建议的重写表明您的联接不恰当地增加了行数(如果在给定日期内不唯一),并建议了子查询,以便它不会使您的行成倍增加。还有其他方法可以做到这一点,但他们的建议很好。换句话说,对于您的问题:tblCc.bidtblC

INNER JOIN是否会导致“in (subquery)”语法重复 避免?

是的。这可能就是重点。或者,他们可能正在尝试调整您的查询,并提供他们认为更快的方法。它可能是也可能不是,但子查询是重点,而不是连接语法。

说到原生的 Oracle 连接语法,与这个论坛上大多数人一直说的相反,它没有错。它从未被弃用,并且仍然有大量仍在使用中。这很大程度上取决于风格和个人使用。这可能是供应商最熟悉的,可能不是他们说你应该改变的。选择您喜欢的任何语法并使用它。

评论

0赞 dougp 11/20/2023
正确答案。比另一个正确答案晚 2 小时。我听到你对逗号式连接的评价。就我个人而言,我发现它们几乎不可能维护。另外,我看到该供应商代码中的子句中重复了同一行(相隔数十行)。如果连接逻辑位于更容易看到错误的语句中,则不会发生这种情况。他们确实使用和,他们只是拒绝使用.阅读和维护非常混乱。WHEREFROMLEFT OUTER JOINRIGHT OUTER JOININNER JOIN