【问题标题】:Combining Two Near Identical MySQL Queries组合两个几乎相同的 MySQL 查询
【发布时间】:2012-07-02 22:28:47
【问题描述】:

这个社区的新手......我不得不说我喜欢这个资源,它太棒了。 :)

(在我更进一步之前,我想指出我已经实现了一个不受欢迎但功能强大的解决方案,它使用多个查询,然后使用 PHP 数组组合我得到的结果,但我'对 MySQL 很弱,我所做的并不优雅或高效,我非常感谢你能给我的任何帮助,以实际帮助我改进它。我的项目使用了几十个 SQL 查询,我'想学会正确地写它们。)

我实际上是在尝试合并两个几乎相同的 MySQL 记录集,使用 UNION 语句或类似的东西。多年来,我一直在寻找解决方案,但在这一点上,它仍然超出了我的范围。所以,这是我的第一个问题:

我的数据结构相对简单,但我怀疑我想要使用它的方式可能不太常见。我有一系列用户定期将数据从他们的移动设备传输到 PHP 服务器,该服务器处理它们并将其内容存储在 MySQL 数据库中。这就是它变得有点不正统的地方,也许——用户实际上是一个封闭链中的链接。在任何时候,每个用户都有一个其他用户作为他们的链接,或者,我更喜欢“目标”,而他们自己则是其他人的目标。 这个模型可以被认为是线性的:A 目标 B,B 目标 C,C 目标 D,D 目标 A。

数据存储在两个表中:

  1. 用户:包含有关用户的数据(例如,用户 ID、姓名、年龄等...目标 ID)
  2. :包含有关所有用户更新的数据(例如,用户 ID、时间戳等...)

收到用户的请求后,我想:

  1. 首先,从 Packages 表中提取最新更新,以及从 Users 表中提取与我们用户的目标相关的传记信息。
  2. 其次,从 Packages 表中提取最新更新,以及从 Users 表中提取与以我们的用户为目标的人有关的传记信息。

这可能有点令人困惑,所以澄清一下: 使用上述模型,如果我收到来自 B 的请求,我希望在单个记录集中返回来自 A 的最新包和来自 C 的最新包,以及相关的传记信息。 我实际上对 B 不感兴趣!

在这一点上,我设法达到的最好的结果涉及三个查询:

  1. 最初,检查用户表以获取我们用户的正确 TargetID。

    SELECT TargetID FROM Users WHERE Users.UserID = [VALUE SUBMITTED IN USER REQUEST];
    
  2. 查询两个表以生成结果 1。

    SELECT Users.UserID, Users.Name, Users.TargetID, Packages.Timestamp, Packages.Latitude, Packages.Longitude, Packages.Message FROM Users, Packages WHERE Packages.UserID = Users.UserID AND Users.UserID = [VALUE OBTAINED FROM QUERY 1] ORDER BY Packages.Timestamp DESC LIMIT 0,1;
    
  3. 查询两个表以生成结果 2。

    SELECT Users.UserID, Users.Name, Users.TargetID, Packages.Timestamp, Packages.Latitude, Packages.Longitude, Packages.Message FROM Users, Packages WHERE Packages.UserID = Users.UserID AND Users.TargetID = [VALUE SUBMITTED IN USER REQUEST] ORDER BY Packages.Timestamp DESC LIMIT 0,1;
    

然后我将结果 1 和 2 合并到一个 PHP 数组中,并将该数组的内容返回给提交请求的用户。在涉及许多此类请求的任何情况下,我都很难相信这种方法是有效的,更不用说理想了。尽管查询 2 和 3 实际上是相同的,并且我确信 WHERE 子句中的简单 OR 条件应该能够将它们组合起来,但如果不为我感兴趣的两个用户返回所有包,我就无法成功地做到这一点,或者,只返回一条记录,丢弃第二条(我显然错误地应用了时间约束)。例如,MySQL 抱怨我有时会错误地同时使用 UNION 和 ORDER BY 语句。每次我尝试修改它时,我都会弄错语法。

我对我当前的解决方案非常不满意,因为此时查看我的项目,这是我的服务器必须比其他所有任务更频繁地执行的单个 MySQL 任务。我确实意识到这个问题相当冗长,但我认为彻底解释事情总是更好,以便第一次可以理解。提前感谢您能给我的任何指导或方向。干杯。

【问题讨论】:

  • 我有点困惑。您说您实际上对 B 并不感兴趣,但在查询 3 中,看起来您正在返回有关 B 的信息,而实际上(如果我理解正确的话)您实际上想要有关 A 的信息?
  • 抱歉,这有点模棱两可,但查询 3 旨在返回与以用户为目标的人相关的数据。为了链接这两个数据表,我使用了:WHERE Packages.UserID = Users.UserID。返回的数据似乎表明它做了我想要的,给我有关目标用户的信息。

标签: mysql union


【解决方案1】:

如果我理解正确,类似:

select 
Users.UserID, 
TargetedPackages.UserID as TargetedID,
TargetedPackages.TimeStamp as TargetedTimestamp,
TargeterPackages.UserID as TargeterID,
TargeterPackages.Timestamp as TargetedTimestamp
from 
Users

INNER JOIN Users as Targeted
on Targeted.TargetId = Users.TargetID

INNER JOIN Users as Targeter
on Targeter.TargetId = Users.UserID

LEFT JOIN Packages as TargetedPackages
on Users.TargetID = TargetedPackages.UserID AND TargetedPackages.Timestamp = (SELECT Max(Timestamp) FROM Packages where Packages.UserID = Users.TargetID)

LEFT JOIN Packages as TargeterPackages
on Targeter.UserID = TargeterPackages.UserID AND TargeterPackages.Timestamp = (SELECT Max(Timestamp) FROM Packages where Packages.UserID = Targeter.UserID)

where Users.UserID = 2

【讨论】:

  • 通过一些崩溃测试,上面的内容似乎是纯粹的魔法。谢谢你的时间。非常感谢。
  • 感谢您的详尽解释。欢迎使用 StackOverflow!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多