2012-03-14 85 views
0

说我有一张3列的表格:version_id,name,value发现版本ID中名称/值对之间的差异

从概念上讲,这个表格有一堆名称 - 值对,每个version_id

如何编写一个查询,该查询仅显示名称值对在版本-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中)

+0

你能举一个小例子吗? – 2012-03-14 01:36:13

+0

我添加了一个例子。 – Muhd 2012-03-14 01:49:48

+0

你试过了:select table_id,name,value from tablename group by concat(name,“”,value) – 2012-03-14 02:03:27

回答

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

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

0

我认为您需要使用几个子查询才能获得所需的结果,因为您正在查找r第一和第二个值。我假设这个名字是“关键”,你必须小组,在这种情况下的东西沿着这些路线应该工作:

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 

快乐查询! :-)

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;