在版本ID中查找名称 - 值对的差异

时间:2012-03-14 01:30:13

标签: mysql

假设我有一个包含3列的表:version_idnamevalue

从概念上讲,此表为每个version_id都有一堆名称 - 值对。

如何编写一个只显示前两个version_ids的名称值对的查询,其中名称值对在版本ID中不相同?

此外,我想知道是否有办法将不同的version_ids并排放置在不同的version_ids中,或者让结果在结果中彼此相邻。

基本上,我想要两个版本的差异。

示例:

version_id    name            value
  23459    jsLibrary2     JQuery_1_4_3
  23459    jsLibrary1     CrossDomainAjax_1_0
  23456    jsLibrary2     JQuery_1_4_2
  23456    jsLibrary1     CrossDomainAjax_1_0
  23456    groovyInclude2 GroovyUtilities
  23454    jsLibrary2     JQuery_1_4_2
  23454    jsLibrary1     CrossDomainAjax_1_0
  23454    groovyInclude2 GroovyUtilities

理想的查询结果:

23456 jsLibrary2     JQuery_1_4_2
23459 jsLibrary2     JQuery_1_4_3
23456 groovyInclude2 GroovyUtilities
23459 NULL           NULL

请注意,理想情况下会注意到新的名称 - 值对(较小的version_id中不存在该名称)和已删除的名称 - 值对(其中名称在较大的version_id中不存在)

3 个答案:

答案 0 :(得分:0)

我认为您需要使用几个子查询来获得所需的结果,因为您正在寻找第一个和第二个值。我假设你的名字是你必须分组的“关键”,在这种情况下,这些内容应该有效:

Select
     firstVersion.firstVersionId,
     firstVersionDetails.name as firstVersionName,
     firstVersionDetails.value as firstVersionValue,
     --second version values will be null if there is no second value
     secondVersion.secondVersionId, 
     secondVersionDetails.name as secondVersionName, --always the same as firstVersionName because name is a key field
     secondVersionDetails.value as secondVersionValue
From
     ( 
           Select 
                name, 
                Max(version_id) as firstVersionId
           From versions
           Group by name
     ) as firstVersion 
     join versions as firstVersionDetails--inner join because every name has a first version
          on firstVersions.version_id = firstVersion.firstVersionId
     left outer Join --outer join so we always get the first version and get the second version whenever there is one (in other words, does *not* limit data to names with at least 2 versions)
     (
           select 
                name, 
                Max(version_id) as secondVersionId
           from versions
           Group by name 
     ) as secondVersion
         on firstVersion.name=secondVersion.name
         and secondVersion.version_id < firstVersion.firstVersionId  --exclude the first version when calculating the 'max'.  This is the part of the join that allows us to identify the second version
     left outer join versions as secondVersionDetails --using outer join again so we don't limit our data to names with 2 versions
          on secondVersion.secondVersionId = secondVersionDetails.version_id

快乐的查询! : - )

答案 1 :(得分:0)

这种方法怎么样 -

SELECT MAX(version_id) INTO @cur FROM tbl;
SELECT MAX(version_id) INTO @prev FROM tbl WHERE version_id < @cur;

SELECT name, @prev, MAX(IF(version_id = @prev, value, '')) AS prev_val, @cur, MAX(IF(version_id = @cur, value, '')) AS cur_val
FROM tbl
WHERE version_id IN (@prev, @cur)
GROUP BY name
HAVING cur_val <> prev_val;

答案 2 :(得分:0)

我确信这可以简化 - 或者至少,我真的希望它可以 - 但是:

SELECT name,
       version_id_before,
       ( SELECT value
           FROM property_history
          WHERE name = t.name
            AND version_id = version_id_before
       ) AS value_before,
       ( SELECT MIN(version_id)
           FROM property_history
          WHERE version_id > version_id_before
       ) AS version_id_after,
       ( SELECT value
           FROM property_history
          WHERE name = t.name
            AND version_id =
                 ( SELECT MIN(version_id)
                     FROM property_history
                    WHERE version_id > version_id_before
                 )
       ) AS value_after
  FROM ( SELECT name,
                CASE WHEN EXISTS
                           ( SELECT 1
                               FROM property_history
                              WHERE name = ph1.name
                                AND version_id =
                                     ( SELECT MAX(version_id)
                                         FROM property_history
                                     )
                           )
                     THEN ( SELECT MAX(version_id)
                              FROM property_history ph2
                             WHERE NOT EXISTS
                                        ( SELECT 1
                                            FROM property_history
                                           WHERE name = ph1.name
                                             AND version_id = ph2.version_id
                                             AND value =
                                                  ( SELECT value
                                                      FROM property_history
                                                     WHERE name = ph1.name
                                                       AND version_id =
                                                            ( SELECT MAX(version_id)
                                                                FROM property_history
                                                            )
                                                  )
                                        )
                          )
                     ELSE ( SELECT MAX(version_id)
                              FROM property_history
                             WHERE name = ph1.name
                          )
                 END AS version_id_before
           FROM property_history ph1
          GROUP
             BY name
       ) AS t
 WHERE version_id_before IS NOT NULL
;

(免责声明:仅使用您的示例数据集进行测试,并为其提供结果:

+----------------+-------------------+-----------------+------------------+--------------+
| name           | version_id_before | value_before    | version_id_after | value_after  |
+----------------+-------------------+-----------------+------------------+--------------+
| groovyInclude2 |             23456 | GroovyUtilities |            23459 | NULL         |
| jsLibrary2     |             23456 | JQuery_1_4_2    |            23459 | JQuery_1_4_3 |
+----------------+-------------------+-----------------+------------------+--------------+

我没有做任何努力来构建其他数据集来测试它。)