停止 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 不知道他们将如何确定是否使用 status
与 url
。【参考方案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 中两次返回相同的结果的主要内容,如果未能解决你的问题,请参考以下文章