How to get second MAXIMUM DATE in MYSQL

后端 未结 4 976
我在风中等你
我在风中等你 2021-01-29 16:27

I want to fetch my record from mysql db. I want to fetch second maximum date from the record. But i failed

Here is my code

    

        
相关标签:
4条回答
  • 2021-01-29 17:10

    You can use simply below query to get second max date in a table or with your requirement : -

    select joiningDate from t_member order by joiningDate desc limit 1,1
    
    0 讨论(0)
  • 2021-01-29 17:12

    Note that the schema setup, QueryA and QueryB are all just for visualization.

    Whereas, QueryC is the one for you to try with your data.

    The reason this does not do a simple order by and limit that @Musa does is simple: you can have many rows with the second greatest date, not one. That is why is uses a variables for @grp and @prevdate to target the second group.

    Schema setup

    -- drop table specimenA;
    create table specimenA
    (   mypk int auto_increment primary key,
        id int not null,    -- note, not autoinc or pk
        theDate date not null,
        title varchar(255) not null,
        otherThing varchar(20) not null
        -- etc
        -- not other indexes whatsoever
    );
    -- truncate table specimenA
    insert specimenA (id,theDate,title,otherThing) values
    (170,'2007-09-19','whatever','whatever'),
    (170,'2008-09-12','whatever','whatever'),
    (170,'2010-01-15','whatever','whatever'),
    (170,'2011-02-03','whatever','whatever'),
    (170,'2012-06-26','whatever','whatever'),
    (170,'2013-03-05','whatever','whatever'),
    (170,'2014-06-25','whatever','whatever'),
    (170,'2015-06-09','whatever','whatever'),
    
    (917,'2009-10-14','whatever','whatever'),
    (917,'2008-12-31','whatever','whatever'),
    
    (109,'2010-04-26','whatever','whatever'),
    (109,'2011-03-02','whatever','whatever'),
    (109,'2012-06-25','whatever','whatever'),
    (109,'2013-01-04','whatever','whatever'),
    (109,'2014-03-28','whatever','whatever'),
    (109,'2015-03-18','whatever','whatever'),
    
    (1057,'2014-03-28','whatever','whatever'),
    (1057,'2014-11-21','whatever','whatever'),
    (1057,'2015-08-13','whatever','whatever');
    

    QueryA

    set @rn:=0,@grp:=0,@prevdate:=''; 
    select id,theDate,title,otherThing,
    @rn:=@rn+1 as rownum, 
    @grp:=if(@prevdate=theDate,@grp,@grp+1) as descGrp, 
    @prevdate:=theDate as unused 
    from specimenA 
    order by theDate DESC -- **** Note this
    -- DESC means greatest first, as is most-recent first for dates
    +------+------------+----------+------------+--------+---------+------------+
    | id   | theDate    | title    | otherThing | rownum | descGrp | unused     |
    +------+------------+----------+------------+--------+---------+------------+
    | 1057 | 2015-08-13 | whatever | whatever   |      1 |       1 | 2015-08-13 |
    |  170 | 2015-06-09 | whatever | whatever   |      2 |       2 | 2015-06-09 |
    |  109 | 2015-03-18 | whatever | whatever   |      3 |       3 | 2015-03-18 |
    | 1057 | 2014-11-21 | whatever | whatever   |      4 |       4 | 2014-11-21 |
    |  170 | 2014-06-25 | whatever | whatever   |      5 |       5 | 2014-06-25 |
    | 1057 | 2014-03-28 | whatever | whatever   |      6 |       6 | 2014-03-28 |
    |  109 | 2014-03-28 | whatever | whatever   |      7 |       6 | 2014-03-28 |
    |  170 | 2013-03-05 | whatever | whatever   |      8 |       7 | 2013-03-05 |
    |  109 | 2013-01-04 | whatever | whatever   |      9 |       8 | 2013-01-04 |
    |  170 | 2012-06-26 | whatever | whatever   |     10 |       9 | 2012-06-26 |
    |  109 | 2012-06-25 | whatever | whatever   |     11 |      10 | 2012-06-25 |
    |  109 | 2011-03-02 | whatever | whatever   |     12 |      11 | 2011-03-02 |
    |  170 | 2011-02-03 | whatever | whatever   |     13 |      12 | 2011-02-03 |
    |  109 | 2010-04-26 | whatever | whatever   |     14 |      13 | 2010-04-26 |
    |  170 | 2010-01-15 | whatever | whatever   |     15 |      14 | 2010-01-15 |
    |  917 | 2009-10-14 | whatever | whatever   |     16 |      15 | 2009-10-14 |
    |  917 | 2008-12-31 | whatever | whatever   |     17 |      16 | 2008-12-31 |
    |  170 | 2008-09-12 | whatever | whatever   |     18 |      17 | 2008-09-12 |
    |  170 | 2007-09-19 | whatever | whatever   |     19 |      18 | 2007-09-19 |
    +------+------------+----------+------------+--------+---------+------------+
    

    And, taking the above select statement, and making it a derived table as alias inR, nested:

    QueryB

    set @rn:=0,@grp:=0,@prevdate:=''; 
    select id,theDate,title,otherthing 
    from 
    (   select id,theDate,title,otherThing,
        @rn:=@rn+1 as rownum, 
        @grp:=if(@prevdate=theDate,@grp,@grp+1) as descGrp, 
        @prevdate:=theDate as unused 
        from specimenA 
        order by theDate DESC  -- **** Note this
    ) inR 
    where descGrp=2;
    +-----+------------+----------+------------+
    | id  | theDate    | title    | otherthing |
    +-----+------------+----------+------------+
    | 170 | 2015-06-09 | whatever | whatever   |
    +-----+------------+----------+------------+
    

    And there is your second greatest date. Meaning second most-recent date.


    So, taking your original select statement, same concept. The motivation for showing the above is simply this: InR is just a Derived Table, no more or less than your select statement that will become a Derived Table.

    QueryC

    set @rn:=0,@grp:=0,@prevdate:=''; 
    
    select client_id, cid, tid, aid, oid, opinion, notification_date,
    ttitle, atitle, otitle, ltitle, stitle,
    opinion_id, pcid, pr_client, address, liaison_one, 
    cityid, head_office_id, city, cname
    from
    (   SELECT r.client_id as client_id,c.id as cid,t.id as tid,a.id as aid,o.id as oid,c.name as opinion, r.notification_date, 
        t.title as ttitle,a.title as atitle,o.title as otitle, l.title as ltitle, s.title as stitle, 
        pr.opinion_id, pc.id as pcid, pr.client_id as pr_client, pc.address, pc.liaison_one, 
        city.id as cityid, pc.head_office_id, city.city, pc.title as cname,
        @rn:=@rn+1 as rownum, 
        @grp:=if(@prevdate=r.notification_date,@grp,@grp+1) as descGrp, 
        @prevdate:=r.notification_date as unused 
    
        FROM og_ratings r 
            LEFT join
        (
          select max(notification_date) notification_date,
            client_id
          from og_ratings
          WHERE notification_date NOT IN (select max(notification_date) FROM og_ratings )
           ) r2
          on r.notification_date = r2.notification_date
          and r.client_id = r2.client_id
        LEFT JOIN og_companies c
        ON r.client_id = c.id
        LEFT JOIN og_rating_types t
        ON r.rating_type_id = t.id
        LEFT JOIN og_actions a
        ON r.pacra_action = a.id
        LEFT JOIN og_outlooks o
        ON r.pacra_outlook = o.id
        LEFT JOIN og_lterms l
        ON r.pacra_lterm = l.id
        LEFT JOIN og_sterms s
        ON r.pacra_sterm = s.id
        LEFT JOIN pacra_client_opinion_relations pr
        ON pr.opinion_id = c.id
        LEFT JOIN pacra_clients pc
        ON pc.id = pr.client_id
        LEFT JOIN city
        ON city.id = pc.head_office_id
        WHERE r.client_id  IN (SELECT opinion_id FROM pacra_client_opinion_relations WHERE client_id = 50)
        order by r.notification_date DESC
    ) inR
    where descGrp=2
    

    QueryC is what you go with. As it is two statements

    • The initialization of the variables
    • and the large query string

    ... you need to run them in that order with query, one for each, in that order, or use PHP multi-query and combine both in one call. That link in previous sentence was for mysqli, the concept is hereby revealed, modify accordingly.

    0 讨论(0)
  • 2021-01-29 17:24

    It wasn't fun to read your query, but I think the problem is here:

    LEFT JOIN (
      SELECT max(notification_date) notification_date, client_id
      FROM og_ratings
      WHERE notification_date NOT IN (
        SELECT max(notification_date)
        FROM og_ratings
    )
    

    if you want the maximum date for every client you need to GROUP BY client_id:

    SELECT client_id, max(notification_date) notification_date
    FROM og_ratings
    GROUP BY client_id
    

    if you want the second maximum there are few options, I'm using this one which is easier to understand but it's not necessarily the most performant:

    SELECT client_id, max(notification_date) notification_date
    FROM og_ratings
    WHERE
      (client_id, notification_date) NOT IN (
        SELECT client_id, max(notification_date)
        FROM og_ratings GROUP BY client_id
      )
    GROUP BY client_id
    

    third problem, you're using a LEFT JOIN which means that you will return all values from og_ratings regardless if they are the second maximum or not. Use INNER JOIN on this context:

    SELECT
      r.client_id,
      c.id,
      t.id,
      ..etc...
    FROM
      og_ratings r INNER JOIN (
        SELECT client_id, max(notification_date) notification_2nd_date
        FROM og_ratings
        WHERE
          (client_id, notification_date) NOT IN (
            SELECT client_id, max(notification_date)
            FROM og_ratings GROUP BY client_id
          )
        GROUP BY client_id
       ) r2
      ON r.notification_date = r2.notification_2nd_date
         AND r.client_id = r2.client_id
      LEFT JOIN og_companies c ON r.client_id = c.id
      LEFT JOIN og_rating_types t ON r.rating_type_id = t.id
      LEFT JOIN og_actions a ON r.pacra_action = a.id
      LEFT JOIN og_outlooks o ON r.pacra_outlook = o.id
      LEFT JOIN og_lterms l ON r.pacra_lterm = l.id
      LEFT JOIN og_sterms s ON r.pacra_sterm = s.id
      LEFT JOIN pacra_client_opinion_relations pr ON pr.opinion_id = c.id
      LEFT JOIN pacra_clients pc ON pc.id = pr.client_id
      LEFT JOIN city ON city.id = pc.head_office_id
    WHERE
      r.client_id IN (
        SELECT opinion_id FROM pacra_client_opinion_relations
        WHERE client_id = 50
      )
    
    0 讨论(0)
  • 2021-01-29 17:27

    You can use ORDER BY DATE_COLUMN DESC LIMIT 1 OFFSET 1. I have appended this code at end of the query:

    SELECT 
        r.client_id,
        c.id,
        t.id,
        a.id,
        o.id,
        c.name as opinion, 
        r.notification_date, 
        t.title as ttitle,
        a.title as atitle,
        o.title as otitle, 
        l.title as ltitle, 
        s.title as stitle, 
        pr.opinion_id, 
        pc.id, 
        pr.client_id as pr_client, 
        pc.address, 
        pc.liaison_one, 
        city.id, 
        pc.head_office_id, 
        city.city, 
        pc.title as cname
    FROM og_ratings r 
        LEFT join (
            select max(notification_date) notification_date,
                client_id
            from og_ratings
            WHERE notification_date NOT IN (select max(notification_date) FROM og_ratings )
       ) r2
      on r.notification_date = r2.notification_date
      and r.client_id = r2.client_id
    LEFT JOIN og_companies c 
        ON r.client_id = c.id
    LEFT JOIN og_rating_types t
        ON r.rating_type_id = t.id
    LEFT JOIN og_actions a
        ON r.pacra_action = a.id
    LEFT JOIN og_outlooks o
        ON r.pacra_outlook = o.id
    LEFT JOIN og_lterms l
        ON r.pacra_lterm = l.id
    LEFT JOIN og_sterms s
        ON r.pacra_sterm = s.id
    LEFT JOIN pacra_client_opinion_relations pr
        ON pr.opinion_id = c.id
    LEFT JOIN pacra_clients pc
        ON pc.id = pr.client_id
    LEFT JOIN city
        ON city.id = pc.head_office_id
    WHERE 
        r.client_id  IN (
            SELECT opinion_id FROM pacra_client_opinion_relations WHERE client_id = 50
        )
    ORDER BY r.notification_date DESC # Add this line
    LIMIT 1 offset 1                  # and this line
    
    0 讨论(0)
提交回复
热议问题