根据2个条件从多个MySQL表中获取最新记录

时间:2013-05-03 14:02:45

标签: mysql sql greatest-n-per-group

我有一个包含serval表的数据库,这些表包含有关我们在各种环境中部署的软件包的信息。然后询问该数据库,以全面了解所安装软件的最新版本,该软件显示在网页的表格中。

我正在尝试做什么,并且正在努力获得每个环境中安装的每个软件包的最新版本。我开始使用这篇文章中的信息:

Retrieving the last record in each group

这对软件的另一个方面有很大帮助,但我倒下的地方是因为我有多个标准可供选择。数据库的相关部分如下

包版本表

package_versions

id
server_name_id
package_name_id
version

包名称表

package_names

id
name

服务器名称表

server_names

id
name
environment_name_id

最后是环境名称表

environment_names

id
name

此结构允许我保存包和部署到各种环境中的版本的历史记录。

现在我需要做的就是获得每个环境中部署的所有软件包的最新版本。正如我所说,当我正在使用一个表格和两个标准时,我在上面的帖子中成功解决了这个问题,但这里有4个表格和2个标准。

我的尝试要么让我回到环境中安装的每个版本:

SELECT  environment_names.name as environment,
        package_names.display as package,
        package_names.name as pkg_name,
        package_versions.version as package_version
FROM    package_versions INNER JOIN package_names ON package_names.id = package_versions.package_name_id
                         INNER JOIN server_names ON server_names.id = package_versions.server_name_id
                         INNER JOIN environment_names ON environment_names.id = server_names.environment_name_id
                         LEFT JOIN package_versions pv ON (package_versions.package_name_id = pv.package_name_id 
                                                           AND package_versions.id < pv.id)
AND     pv.id IS NULL
ORDER BY environment_names.name, package_names.name

不可能只在版本号上使用Max,因为它是由Maven生成的,因此它的格式为x.x.x,并且可以包含SNAPSHOT。

其他尝试只是为我提供了安装在任何地方的最新版本。

我想我需要在LEFT加入部分添加一些东西,但我真的很难弄清楚什么。感谢任何帮助。

非常感谢,

拉塞尔

3 个答案:

答案 0 :(得分:1)

您需要的是MySQL目前不提供的排名功能。有一种方法可以模拟它。此外,您需要拆分版本值,以便对它们进行排序。

Select envName, pkgName, version
From (
      Select envName, pkgName, version
        , @rnk := if(@env=envId && @pkg=package_name_id, if(@pkgVer=verId, @rnk, @rnk + 1), 1) As rnk
        , @pkgVer := verId
        , @env := envId
        , @pkg := package_name_id
      From (
            Select env.id As envId
              , env.name As envName
              , ver.package_name_id
              , pkg.name As pkgName
              , ver.id As verId
              , ver.version
              , Cast(Substring_Index( ver.version , '.', 1 ) As signed) As Major
              , Cast(Substring_Index(Substring_Index( ver.version , '.', 2 ),'.',-1) As signed) As Minor
              , Cast(Substring_Index(Substring_Index( ver.version , '.', -2 ),'.',1) As signed) As Build
              , Cast(Substring_Index( ver.version , '.', -1 ) As signed) As Revision
            From package_versions As ver
              Join package_names As pkg
                On pkg.id = ver.package_name_id
              Join server_names As sys
                  On sys.id = ver.server_name_id
              Join environment_names As env
                  On env.id = sys.environment_name_id
              Cross Join ( Select @rnk := 0
                              , @ver := ''
                              , @env := 0
                              , @pkg := 0 ) As Z
          ) As envPackages
      Order By envName, pkgName, Major Desc, Minor Desc, Build Desc, Revision Desc
      ) As rnkedPackages
Where rnk = 1
Order By envName, pkgName, rnk

SQL Fiddle

答案 1 :(得分:0)

SELECT environment_names.name as environment,
       package_names.display as package,
       package_names.name as pkg_name,
       MAX(package_versions.version) as package_version
FROM package_versions 
INNER JOIN package_names ON package_names.id = package_versions.package_name_id                             
INNER JOIN server_names ON server_names.id = package_versions.server_name_id                             
INNER JOIN environment_names ON environment_names.id = server_names.environment_name_id
GROUP BY environment_names.name,
         package_names.display,
         package_names.name
ORDER BY environment_names.name, package_names.name

答案 2 :(得分:0)

所有

非常感谢所有的建议,他们都帮了忙。

我放在package_versions.id或package_versions.deploy_time周围的MAX()函数都没有正常工作。我似乎得到了最新的版本ID,但实际版本号与该记录不匹配。

我计算出这是因为我需要使用两个表来获取环境名称。我现在已经添加了一个与PackageVersions表的关系,这样我就不必使用服务器表作为中介。所以现在表格如下:

包版本表

package_versions

id
package_name_id
environment_name_id
version

(server_name_id仍在那里,以便我可以使用它给我更详细的环境信息)。

包名称表

package_names

id
name

环境名称表

environment_names

id
name

现在我的SQL查询如下:

SELECT  package_versions.id,
        environment_names.name,
        package_names.name,
        package_versions.version,
        max(package_versions.id)
FROM    package_versions INNER JOIN environment_names ON package_versions.environment_name_id = environment_names.id
                         INNER JOIN package_names ON package_names.id = package_versions.package_name_id
GROUP BY environment_names.id, package_names.name                        
ORDER BY environment_names.name, package_names.name;

现在这给了我所需的信息,并与我用这个新代码替换的系统相匹配。

感谢Lucas和Nagaski的建议。

罗素