SQL从“所有时间记录”返回第一个记录日期

时间:2014-10-13 16:29:14

标签: php mysql sql

存储所有时间记录的钓鱼数据库。但是,当有人有联合记录时,我想恢复到第一次捕获作为真实记录。

select * 
from T 
inner join (select Type, 
                   Name, 
                   max(TotDrams) as maxdrams 
            from T 
            WHERE Type='Common Bream' 
            group by Type, Name 
           ) sq on T.Type = sq.Type 
                and T.Name = sq.Name 
                and sq.maxdrams = T.TotDrams 
ORDER BY Ranking ASC

以上内容返回每个名称具有最佳捕获的所有时间记录,但是当记录是联合时,它自然会返回附加记录。我只希望将最早的日期记录包含在所有时间记录中。

有没有办法调整上面的代码来删除额外的联合记录,只挑选最早的记录?

Fishname     Rank            Weight           Angler            Date

Slimey       Rank 1        2 lb   3 oz      John Budd         30/11/2013
Fishy        Rank 2        1 lb   15 oz     Chris Clot        12/01/2009
Scales       Rank 3        1 lb   12 oz     John Budd         21/03/2014
Scales       Rank 3        1 lb   12 oz     Harry White       01/04/2002

通过上面的例子 - 这是目前正在发生的事情,我想删除John Budd的联合记录,因为它是联合的而不是原始的。

另一个注意事项: - 这个SQL将与php一起使用。

3 个答案:

答案 0 :(得分:1)

您可以在每条鱼捕获的最早日期添加另一个连接。类似的东西:

select * 
from T 
inner join (select Species, 
                   FishName, 
                   max(TotalDrams) as maxdrams 
            from T 
            WHERE Species='Common Bream' 
            AND DateCaught <> ''
            group by Species, FishName 
           ) sq on T.Species = sq.Species 
                and T.FishName = sq.FishName 
                and sq.maxdrams = T.TotalDrams 
inner join (select Species, 
                   FishName, 
                   min(DateCaught) as minDate 
            from T 
            WHERE Species='Common Bream' 
            AND DateCaught <> ''
            group by Species, FishName 
           ) sq2 on T.Species = sq2.Species 
                and T.FishName = sq2.FishName 
                and sq2.minDate = T.DateCaught 
where T.DateCaught <> ''
ORDER BY Rank ASC

接下来,您可以将2个标准重构为单个联接:

select * 
from T 
inner join (select Species, 
                   FishName, 
                   max(TotalDrams) as maxdrams,
                   min(DateCaught) as minDate 
            from T 
            WHERE Species='Common Bream' 
            AND DateCaught <> ''
            group by Species, FishName 
           ) sq on T.Species = sq.Species 
                and T.FishName = sq.FishName 
                and sq.maxdrams = T.TotalDrams 
                and sq.minDate = T.DateCaught 
where T.DateCaught <> ''
ORDER BY Rank ASC

编辑:

对数据结构的进一步分析表明,上面的答案并不完全正确 - 由于日期是varchar,它过滤掉了几条记录,而且对数据结构的假设也不正确。修改后的答案如下:

select distinct 
   T.species,
   t.fishname,
   t.rank,
   t.pounds,
   t.ounces,
   t.drams,
   t.totaldrams,
   t.peg,
   t.angler,
   sq.*,
   sq2.*
FROM (select Species, 
             FishName, 
              max(TotalDrams) as maxdrams
      from T 
      WHERE Species='Common Bream' 
      group by Species, FishName 
     ) sq 
inner join (select Species, 
                   FishName, 
                   TotalDrams,
                   min(if(DateCaught='',STR_TO_DATE('31/12/3099','%d/%m/%Y'),STR_TO_DATE(DateCaught,'%d/%m/%Y'))) as minDate 
            from T 
            WHERE Species='Common Bream' 
            group by Species, FishName, TotalDrams 
           ) sq2 on sq.Species = sq2.Species 
                 and sq.FishName = sq2.FishName 
                 and sq.MaxDrams = sq2.TotalDrams
inner join T on sq.species = T.species 
and sq.fishname = T.fishname
and sq.maxdrams = T.totaldrams
and sq2.mindate = if(DateCaught='',STR_TO_DATE('31/12/3099','%d/%m/%Y'),STR_TO_DATE(DateCaught,'%d/%m/%Y'))

答案 1 :(得分:0)

排名后按日期排序,然后按鱼名分组。看起来有用吗?

select * from T inner join (select Species, FishName, max(TotalDrams) as maxdrams from T WHERE Species='Common Bream' group by Species, FishName ) sq on T.Species = sq.Species and T.FishName = sq.FishName and sq.maxdrams = T.TotalDrams GROUP BY T.FishName ORDER BY Rank, DateCaught ASC

答案 2 :(得分:0)

我接近这个的方式略有不同,而不是试图将结果限制到最大值,我会排除不是的结果。所以使用类似的东西:

SELECT  T.*
FROM    T
        LEFT JOIN T AS T2
            ON T2.Species = T.Species
            AND T2.FishName = T.FishName
            AND (T2.TotalDrams < T.TotalDrams
                OR (T.TotalDrams = T2.TotalDrams AND T2.DateCaught > T.DateCaught))
WHERE   T.Species = 'Common Bream'
AND     T2.Species IS NULL
ORDER BY T.Rank ASC;

这使用标准的LEFT JOIN/IS NULL方法来排除相同鱼类类型的记录,并且:

  • TotalDrams
  • 的值较低

  • TotalDrams 后来的DateCaught
  • 具有相同的值

<强> Example on SQL Fiddle

由于MySQL实现子查询的方式,您可能会发现这比没有提供所需结果的原始查询表现更好!


修改

好的,新方法。我认为最好的解决方法是使用变量为每条记录存储一个新的行号,然后你可以过滤顶部1.以下将根据订购标准分配你的行号:

SELECT  @r:= CASE WHEN @f = t.FishName AND @s:= t.Species 
                    THEN @r + 1 
                ELSE 1 
            END AS RowNum,
        @f:= t.FishName AS FishName,
        @s:= t.Species AS Species,
        t.Rank,
        t.Pounds,
        t.Ounces,
        t.Drams,
        t.TotalDrams,
        t.Peg,
        t.Angler,
        STR_TO_DATE(IF(t.DateCaught = '', '31/12/2050', t.DateCaught), '%d/%m/%Y')  AS DateCaught
FROM    T
        CROSS JOIN (SELECT  @f:= '',@s:='', @r:= 0) AS v
ORDER BY t.FishName, t.Species, t.TotalDrams DESC, DateCaught ASC;

然后你可以把它放到子查询中,并将记录限制在前1:

SELECT  *
FROM    (   SELECT  @r:= CASE WHEN @f = t.FishName AND @s = t.Species 
                                THEN @r + 1 
                            ELSE 1 
                        END AS RowNum,
                    @f:= t.FishName AS FishName,
                    @s:= t.Species AS Species,
                    t.Rank,
                    t.Pounds,
                    t.Ounces,
                    t.Drams,
                    t.TotalDrams,
                    t.Peg,
                    t.Angler,
                    t.DateCaught
            FROM    T
                    CROSS JOIN (SELECT  @f:= '',@s:='', @r:= 0) AS v
            ORDER BY t.FishName, t.Species, t.TotalDrams DESC, STR_TO_DATE(IF(t.DateCaught = '', '31/12/2050', t.DateCaught), '%d/%m/%Y') ASC
        ) AS t
WHERE   t.RowNum = 1
ORDER BY t.Rank ASC;

<强> Example on SQL Fiddle

这是最灵活的方法,如果您想添加更多规则,即如果您有两个相同的权重,并且在同一日期,您可以为子查询添加进一步的排序,例如Angler。这保证了(鱼名,物种)每个元组只有一个记录,并且给定足够的排序确定性结果。