停止 SQL 在 JOIN 中两次返回相同的结果

Posted

技术标签:

【中文标题】停止 SQL 在 JOIN 中两次返回相同的结果【英文标题】:Stop SQL returning the same result twice in a JOIN 【发布时间】:2012-08-31 14:53:50 【问题描述】:

我已经将几个表连接在一起以获取我想要的数据,但由于我是 SQL 新手,所以我无法弄清楚如何停止多次返回数据。

她的 SQL 语句;

SELECT
   T.url,
   T.ID,

   S.status,
   S.ID,

   E.action,
   E.ID,
   E.timestamp

FROM tracks T, status S, events E
WHERE S.ID AND T.ID = E.ID

ORDER BY E.timestamp DESC

返回的数据是这样的;

+----------------------------------------------------------------+
| URL | ID | Status | ID | action               | ID | timestamp |
+----------------------------------------------------------------+
| T.1 | 4  | hello  | 4  | has uploaded a track | 4  | time      |
| T.2 | 3  | bye    | 3  | has some news        | 3  | time      |
| t.1 | 4  | more   | 4  | has some news        | 4  | time      |
+----------------------------------------------------------------+

这是一个非常基本的示例,但确实概述了发生的情况。如果您查看第三行,则当状态不同时,该 URL 会重复。

这就是我想要发生的事情;

+-------------------------------------------------------+
| URL or Status | ID | action               | timestamp |
+-------------------------------------------------------+
| T.1           | 4  | has uploaded a track | time      |
| hello         | 3  | has some news        | time      |
| bye           | 4  | has some news        | time      |
+-------------------------------------------------------+

请注意,当操作上传曲目时,会显示 url(在本例中模拟的是 T.1)。这个非常重要。在触发状态或轨道插入时插入事件表中的操作。如果插入了新曲目,则操作是“已上传曲目”,您猜它是什么状态。此时 ID 和时间戳也被插入到事件表中。

注意:查询中包含更多表,实际上还有 3 个,但为简单起见,我将它们省略了。

【问题讨论】:

既然您是 SQL 新手,您应该知道隐式连接是一种 SQL 反模式,您应该学习使用显式连接。 【参考方案1】:

不要使用 20 年过时的语法。尽管许多 RDBMS 支持 FROM a, b, c 样式语法,但我使用过的所有系统都已弃用它。 (我还没有使用过所有东西,但强烈建议不要使用这种风格。)

改为使用 ANSI-92 标准 JOIN 语法。那就更难搞错了……

SELECT
  *
FROM
  status S
INNER JOIN
  tracks T
    ON T.ID = S.ID
INNER JOIN
  events E
    ON E.ID = S.ID
ORDER BY
  E.timestamp DESC 

此外,您的示例数据表明您在表 S...中有以下内容...

 Status | ID
--------+----
 hello  | 4
 bye    | 3
 more   | 4

ID = 4 有两行。如果您真的希望 T 中的每一行只连接 S 中的一行,您应该选择哪一行?应该删除一个,还是您有其他逻辑/条件可以用来选择两者之一?

【讨论】:

如果我愿意,我会为你投票一百万次。使用隐式语法实际上没有任何借口。但是,它并非在所有系统中都被弃用。在 SQL Server 中,仅不推荐使用外连接隐式语法(无论如何它从未正常工作,这是原因的一部分)。刚接触 SQl 的人需要了解连接,隐式连接更有可能对初学者来说是不正确的。 FROM a, b, c 仍在教授和使用中。这也不能解决 OP 的预期结果。 感谢您的信息,没有意识到它已被弃用。我正在使用的教程是使用旧的东西。因为它都在新闻提要中返回,所以应该返回来自该 ID 的每个状态,然后按时间戳排序。 @njk - 请阅读指出S.ID = 4 由两行组成的部分?它指出需要额外的逻辑来确定在 上加入哪一行(或者,也许这个例子不正确?或者,也许数据需要清理?) @Dems 如果您在我的回答中阅读了 OP 的评论,OP 不知道他们将如何确定是否使用 statusurl【参考方案2】:

尝试使用分组方式;

SELECT T1.url, T1.id, S1.estatus, S1.id, E1.action, E1.id, E1.timestamp FROM t T1, s S1, e E1 WHERE S1.id AND T1.id = E1.id GROUP BY S1.id ORDER BY E1.timestamp DESC;

【讨论】:

【参考方案3】:

改变这个

WHERE S.ID AND T.ID = E.ID

到这里

WHERE S.ID = E.ID AND T.ID = E.ID

更新

有些人对使用隐式连接表示法非常敏感。为了安抚这些人并作为更好的做法,您应该使用明确的JOIN 语句。

【讨论】:

那没有达到预期的效果。不太清楚如何解释它,但请看看结果应该是什么样子来解释需要发生的事情 试试WHERE T.ID = S.ID AND S.ID = E.ID 啊哈,那么确定使用status 而不是url 的逻辑是什么? 根本不要使用FROM a, b, c WHERE x。使用INNER JOIN。 Ansi-92 年近 20 岁。甚至支持 , 表示法的 RDBMS 也已弃用它并建议不要使用它。不要这样做。 我会否决任何鼓励初学者使用隐式语法的人。它是 SQL 反模式,我们应该避免推荐使用反模式。【参考方案4】:

感谢所有的答案,他们帮助了很多。我已经使用 php 中的 if 语句进行了一个有效的查询并操纵了结果。

在这里;

SELECT 
T.url AS track_url,

S.status,

E.action,
E.ID,
E.timestamp,

A.name,
A.url AS artist_url

FROM events E

LEFT JOIN 
TRACKS T
ON T.ID = E.ID AND E.action = 'has uploaded a track.'

LEFT JOIN  
STATUS S
ON S.ID = E.ID AND E.action = 'has some news.'

LEFT JOIN 
ARTISTS A
ON A.ID = E.ID

ORDER BY E.timestamp DESC

它的结果是很多 NULL 列,但这很好,因为它可以工作!如果ID 没有上传曲目,则相关列是NULL,这同样适用于查询的其他位。 ID 不会重复,因为仅选择了事件表中的 ID

如果您发现任何我可能忽略的问题,请大声疾呼!

【讨论】:

以上是关于停止 SQL 在 JOIN 中两次返回相同的结果的主要内容,如果未能解决你的问题,请参考以下文章

如何防止在node.js中两次调用相同URL的获取

在 SQL 中,为啥这个 JOIN 会两次返回键列?

在php中两次调用相同的函数时出错

如何在同一列或不同列的一个sql语句中两次使用'BETWEEN'条件

如何以不同的条件选择相同的字段两次并将结果显示为单独的字段

如果它们位于两个 Web 应用程序中,Tomcat 是不是会将相同的库文件加载到内存中两次?