简体   繁体   中英

Get contents of next row based on date in previous row

I have a history table which contains changes made to data and the date the change was made - the history are the old values and the date the change was made.

There is then a main table which contains the current values.

The actual table layouts are like:

history

id user_id colour change_date
1  1       Red    2016-01-01 
2  1       Blue   2016-04-05
3  1       Green  2016-08-05

and then:

current

user_id colour entry_date
1       Yellow 2015-10-14 

I want to try and get a chronological list of all the values so the output for user_id 1 would look like:

2015-10-14 Red
2016-01-01 Blue
2016-04-05 Green
2016-08-05 Yellow

At the moment I am taking each user in the user table and checking if they have a history value - if they do not then the output simply is:

2015-10-14 Yellow

However, when they do have a history I am having to start with the entry date and assign the first colour history to that and storing in an array.

Then I take the first history date and get the second history value (via another query) and store that in the array and loop and so on - there are 150k users and each one can have 20 or 30 changes and it is horribly inefficient!

I would like to find a more efficient way of doing this either in PHP or MySQL - can anyone help?

Firstly, I am unsure what connection class you have decided to use but for this, I'll provide a class I wrote to query which uses PDO.

class Entity extends PDO {
    public function __construct(
    ) {
        try {
            parent::__construct(
               'mysql:host=localhost;dbname=example',
               'db_user',
               'db_pass'
            );
        } catch (PDOException $ex) {
            die($ex->getMessage());
        }
    }

    public function query(
        $statement,
        $values = array()
    ) {
        $stmp = parent::Prepare($statement);
        $stmp->execute($values);
        return $stmp;
    }
}

Now, assuming you already know the user_id you can begin to now query through the database to retrieve the change logs.

$con = new Entity();
$user_id_example = 1;

$sql = 'SELECT colour, change_date FROM history WHERE user_id = ? ORDER BY change_date ASC';

var_dump($con
    ->query($sql, [$user_id_example])
    ->fetchAll()
);

Update: If you're trying to get the newest change log you can add an LIMIT to your query

$sql = 'SELECT colour, change_date FROM history WHERE user_id = ? ORDER BY change_date ASC LIMIT 1';

Update: Note, if you want to bring results out of both table current and history, you can use an INNER JOIN

$sql = 'SELECT colour, change_date FROM history h INNER JOIN current c ON h.change_date = c.change_date WHERE user_id = ? ORDER BY change_date ASC';

I propose you two querys, in the first one you will have the colours ordered and in the second one you will have the dates ordered, so, in php you will have two arrays with the data and only remains to put together the data.
There is the code, only you have to set the conection to the database

$sqlColour = "select c.user_id, u.colour from current as c inner join ( select user_id, colour from history union all select user_id , colour from current ) u on c.user_id=u.user_id";
$sqlDate = "select c.user_id, u.date from current as c inner join ( select user_id, entry_date as date from current union all select user_id , change_date as date from history ) u on c.user_id=u.user_id";

$stmt = $db->query($sqlColour);
$colours = $stmt->fetchAll();
$stmt = $db->query($sqlDate);
$dates = $stmt->fetchAll();

$answer = array();
for ($i = 0; $i < count($colours); $i++) {
    $answer[] = array("date" => $dates[$i]['date'], "colour" => $colours[$i]['colour'], "user_id" => $colours[$i]['user_id']);
}
echo $answer;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM