【问题标题】:Compare version numbers in a SQL query比较 SQL 查询中的版本号
【发布时间】:2015-09-30 01:28:49
【问题描述】:

我有一个表格,用于存储特定软件版本的兼容性。例如客户端的版本是否与后端兼容。有一个下限和一个上限,两者都有主要、次要和修订版本号。上限数字可以为空(有一个检查约束可确保它们全部或都不为空)。

我想创建一个查询,它返回各种majorVersion、minorVersion 和revisionVersion 编号的行。 示例(省略了 clientId 以使其更简单):

minMajorVersion | minMinorVersion | minRevisionVersion | maxMajorVersion | maxMinorVersion | maxRevisionVersion
1                 0                 0                    NULL              NULL              NULL
1                 2                 5                    NULL              NULL              NULL
1                 3                 0                    NULL              NULL              NULL
2                 0                 1                    5                 1                 0

假设我想知道哪个客户端版本与后端版本 1.2.6 兼容。为此,查询应返回前两行,因为最小版本较小,而最大版本为 NULL。 对于另一个后端版本 2.0.1,查询应该返回最后一行,而对于后端版本 5.2.0,查询应该不返回任何内容。

我能够创造的是这样的:

SELECT c.* FROM COMPATIBILITYQUALIFIER q
join client c on (c.id = q.clientid)
WHERE (q.MINBACKENDMAJORVERSION < 2
OR (q.MINBACKENDMAJORVERSION = 2 AND q.MINBACKENDMINORVERSION < 3) 
OR (q.MINBACKENDMAJORVERSION = 2 AND q.MINBACKENDMINORVERSION = 3 AND q.MINBACKENDREVISIONVERSION <=6))
AND ((q.MAXBACKENDMAJORVERSION IS NULL) 
  OR ((q.MAXBACKENDMAJORVERSION > 2) 
    OR (q.MAXBACKENDMAJORVERSION = 2 AND q.MAXBACKENDMINORVERSION > 3)
    OR (q.MAXBACKENDMAJORVERSION = 2 AND q.MAXBACKENDMINORVERSION = 3 AND q.MAXBACKENDREVISIONVERSION >= 6)))
order by c.MAJORVERSION DESC, c.MINORVERSION DESC, c.REVISIONVERSION DESC; 

我不认为它会是高性能的。 一种简单的方法是创建一个存储过程,但我现在不想将代码放入数据库中。

有没有办法用子查询来做到这一点?还有什么快的吗?

已更新。

【问题讨论】:

  • 没有实际的表+数据定义+你尝试过的查询,很难给出正确的答案。
  • 您的要求不明确。请提供示例数据并更好地描述您要解决的问题。
  • @sstan 谢谢,你们都是对的。抱歉,当我发布问题时我有点累了。现在我更新了,请再看看。
  • @Sentinel 你能再看看我的问题吗?我更新了。

标签: sql oracle


【解决方案1】:

当然,查询不是最漂亮的。但仅仅因为你有多个这样的条件子句并不意味着你的查询会更慢。

仅出于可读性和避免重复硬编码值的考虑,我会将查询重写为如下内容:

select c.*
  from compatibilityqualifier q
  join (select 2 as major,
               3 as minor,
               6 as revision
          from dual) ver
    on 1=1
  join client c
    on c.id = q.clientid
 where ver.major >= q.minBackendMajorVersion
   and (ver.major > q.minBackendMajorVersion or ver.minor >= q.minBackendMinorVersion)
   and (ver.major > q.minBackendMajorVersion or ver.minor > q.minBackendMinorVersion or ver.revision >= q.minBackendRevisionVersion)
   and (q.maxBackendMajorVersion is null
        or (ver.major <= q.maxBackendMajorVersion
            and (ver.major < q.maxBackendMajorVersion or ver.minor <= q.maxBackendMinorVersion)
            and (ver.major < q.maxBackendMajorVersion or ver.minor < q.maxBackendMinorVersion or ver.revision <= q.maxBackendRevisionVersion)
        )
   )
 order by c.majorversion desc,
          c.minorversion desc,
          c.revisionversion desc

但我希望性能几乎相同。

【讨论】:

    【解决方案2】:

    对于表示为 (Major, Minor, Revision) 元组的任何给定版本号,您可以使用以下查询从 CompatibilityQualifier 表中检索行。例如下面的版本 1、2、6:

    select q.*
      from (select 1 major
                 , 2 minor
                 , 6 revision from dual) v
      join CompatibilityQualifier q
        on ( q.minMajorVersion < v.major or
             ( q.minMajorVersion = v.major and
               ( q.minMinorVersion < v.minor or
                 ( q.minMinorVersion = v.minor and
                   q.minRevisionVersion <= v.revision))))
       and ( q.maxMajorVersion is null or
             q.maxMajorVersion > v.major or
             ( q.maxMajorVersion = v.major and
               ( q.MaxMinorVersion is null or
                 q.MaxMinorVersion > v.minor or
                 ( q.MaxMinorVersion = v.minor and
                   ( maxRevisionVersion is null or
                     q.maxRevisionVersion >= v.revision)))));
    

    这会产生以下结果:

    | MINMAJORVERSION | MINMINORVERSION | MINREVISIONVERSION | MAXMAJORVERSION | MAXMINORVERSION | MAXREVISIONVERSION |
    |-----------------|-----------------|--------------------|-----------------|-----------------|--------------------|
    |               1 |               0 |                  0 |          (null) |          (null) |             (null) |
    |               1 |               2 |                  5 |          (null) |          (null) |             (null) |
    

    对于版本 2,0,1,CompatibilityQualifier 中的每一行都将返回,因为 1,x,x 记录中的任何一个都没有上限。

    如果您确实希望在查询的主要版本号与minMajorVersion 不同时从结果集中排除具有NULL 值为maxMajorVersion 的记录,那么您可以使用此修订版本:

    select q.*
      from (select 2 major
                 , 0 minor
                 , 1 revision from dual) v
      join CompatibilityQualifier q
        on ( q.minMajorVersion < v.major or
             ( q.minMajorVersion = v.major and
               ( q.minMinorVersion < v.minor or
                 ( q.minMinorVersion = v.minor and
                   q.minRevisionVersion <= v.revision))))
       and ( --q.maxMajorVersion is null or
             q.maxMajorVersion > v.major or
             ( coalesce(q.maxMajorVersion  -- When Null compare to minMajorVersion
                       ,q.minMajorVersion) = v.major and
               ( q.MaxMinorVersion is null or
                 q.MaxMinorVersion > v.minor or
                 ( q.MaxMinorVersion = v.minor and
                   ( maxRevisionVersion is null or
                     q.maxRevisionVersion >= v.revision)))));
    

    只返回一行:

    | MINMAJORVERSION | MINMINORVERSION | MINREVISIONVERSION | MAXMAJORVERSION | MAXMINORVERSION | MAXREVISIONVERSION |
    |-----------------|-----------------|--------------------|-----------------|-----------------|--------------------|
    |               2 |               0 |                  1 |               5 |               1 |                  0 |
    

    【讨论】:

    • 注意:当查询的版本为 2.0.1 或 5.2.0 时,为了使查询不返回版本 1 行,那么 CompatibilityQualifier 表的硬最大值需要为 2.0.0对于每个 1.x.x 修订记录或更低的最大值或 1.null.null 的较软最大值,例如 1.10.265 或 1.30.null。
    猜你喜欢
    • 2016-04-24
    • 2022-01-23
    • 2010-12-15
    • 1970-01-01
    • 1970-01-01
    • 2022-10-24
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    相关资源
    最近更新 更多