基于2个条件从多个MySQL表中获取最新记录

基于2个条件从多个MySQL表中获取最新记录,mysql,sql,greatest-n-per-group,Mysql,Sql,Greatest N Per Group,我有一个包含多个表的数据库,这些表保存了我们部署到各种环境中的包的信息。然后对该数据库进行查询,以提供所安装软件的最新版本的总体情况,并在网页上的表格中显示 我正在努力做的是,获取每个环境中安装的每个软件包的最新版本。我开始使用这篇文章中的信息: 这对软件的另一个方面有很大帮助,但我的失败是因为我有不止一个选择的标准。数据库的相关部分如下所示 包版本表 package_versions id server_name_id package_name_id version 包名称表 packa

我有一个包含多个表的数据库,这些表保存了我们部署到各种环境中的包的信息。然后对该数据库进行查询,以提供所安装软件的最新版本的总体情况,并在网页上的表格中显示

我正在努力做的是,获取每个环境中安装的每个软件包的最新版本。我开始使用这篇文章中的信息:

这对软件的另一个方面有很大帮助,但我的失败是因为我有不止一个选择的标准。数据库的相关部分如下所示

包版本表

package_versions

id
server_name_id
package_name_id
version
包名称表

package_names

id
name
server_names

id
name
environment_name_id
服务器名称表

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
选择环境\u name.name作为环境,
包名称。显示为包,
package_names.name作为包装名称,
package_versions.version作为package_version
从包\u版本内部连接包\u名称上的包\u名称。id=包\u版本。包\u名称\u id
服务器上的内部联接服务器名称\u names.id=包\u versions.server\u name\u id
内部联接环境\u name ON environment\u names.id=服务器\u name.environment\u name\u id
左连接包\u版本pv ON(包\u版本.package\u名称\u id=pv.package\u名称\u id
和包_versions.id
不可能只在版本号上使用Max,因为它是由Maven生成的,所以它的格式是x.x.x,并且可以包含快照

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

我想我需要在左连接部分添加一些东西,但我真的很难弄清楚是什么。我们衷心感谢您的帮助

非常感谢


Russell

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

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
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

您需要的是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
全部

非常感谢所有的建议,他们都很有帮助

我在package_versions.id或package_versions.deploy_time中使用的MAX()函数都不能正常工作。例如,我似乎获得了最新的版本id,但实际的版本号与该记录不匹配

我发现这是因为我需要使用两个表来获取环境名称。现在,我向PackageVersions表添加了一个关系,这样我就不必将服务器表用作中介。现在这些表看起来像:

包版本表

package_versions

id
package_name_id
environment_name_id
version
(服务器名称\u id仍然在那里,以便我可以使用它来提供有关环境的更详细信息)

包名称表

package_names

id
name
environment_names

id
name
环境名称表

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;
这是现在给我的信息,我需要和匹配的系统,我更换了这个新的代码

感谢卢卡斯和长崎的建议

拉塞尔

非常感谢所有的建议,他们都很有帮助

我在package_versions.id或package_versions.deploy_time中使用的MAX()函数都不能正常工作。例如,我似乎获得了最新的版本id,但实际的版本号与该记录不匹配

我发现这是因为我需要使用两个表来获取环境名称。现在,我向PackageVersions表添加了一个关系,这样我就不必将服务器表用作中介。现在这些表看起来像:

包版本表

package_versions

id
package_name_id
environment_name_id
version
(服务器名称\u id仍然在那里,以便我可以使用它来提供有关环境的更详细信息)

包名称表

package_names

id
name
environment_names

id
name
环境名称表

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;
这是现在给我的信息,我需要和匹配的系统,我更换了这个新的代码

感谢卢卡斯和长崎的建议


Russell

如果它的主/次/发布[-SNAPSHOT]版本控制,您将需要一个更复杂的排序算法。否则1.10在1.2之前。。。你能不能把它转换成代码?卢卡斯,是的,这就是我想要避免的。我希望在一次查询中从数据库中获取所有数据,而不是执行较小的查询。我原以为我可以使用左连接技巧,但这可能太过分了。你可以尝试编写一个函数来拆分版本并比较每个段,但由于mysql没有拆分函数,这可能非常困难。任何事情都可以用足够的代码来完成,但当您将其分解为代码时,您会发现这要简单得多……如果其主要/次要/发布[-SNAPSHOT]版本控制,您将需要更复杂的排序算法。否则1.10在1.2之前。。。你能不能把它转换成代码?卢卡斯,是的,这就是我想要避免的。我想一次把所有的数据都拿回来