MySQL JOIN the most recent row only?

后端 未结 8 1362
傲寒
傲寒 2020-11-28 03:06

I have a table customer that stores a customer_id, email and reference. There is an additional table customer_data that stores a historical record of the changes made to the

8条回答
  •  离开以前
    2020-11-28 03:19

    I know this question is old, but it's got a lot of attention over the years and I think it's missing a concept which may help someone in a similar case. I'm adding it here for completeness sake.

    If you cannot modify your original database schema, then a lot of good answers have been provided and solve the problem just fine.

    If you can, however, modify your schema, I would advise to add a field in your customer table that holds the id of the latest customer_data record for this customer:

    CREATE TABLE customer (
      id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
      current_data_id INT UNSIGNED NULL DEFAULT NULL
    );
    
    CREATE TABLE customer_data (
       id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
       customer_id INT UNSIGNED NOT NULL, 
       title VARCHAR(10) NOT NULL,
       forename VARCHAR(10) NOT NULL,
       surname VARCHAR(10) NOT NULL
    );
    

    Querying customers

    Querying is as easy and fast as it can be:

    SELECT c.*, d.title, d.forename, d.surname
    FROM customer c
    INNER JOIN customer_data d on d.id = c.current_data_id
    WHERE ...;
    

    The drawback is the extra complexity when creating or updating a customer.

    Updating a customer

    Whenever you want to update a customer, you insert a new record in the customer_data table, and update the customer record.

    INSERT INTO customer_data (customer_id, title, forename, surname) VALUES(2, 'Mr', 'John', 'Smith');
    UPDATE customer SET current_data_id = LAST_INSERT_ID() WHERE id = 2;
    

    Creating a customer

    Creating a customer is just a matter of inserting the customer entry, then running the same statements:

    INSERT INTO customer () VALUES ();
    
    SET @customer_id = LAST_INSERT_ID();
    INSERT INTO customer_data (customer_id, title, forename, surname) VALUES(@customer_id, 'Mr', 'John', 'Smith');
    UPDATE customer SET current_data_id = LAST_INSERT_ID() WHERE id = @customer_id;
    

    Wrapping up

    The extra complexity for creating/updating a customer might be fearsome, but it can easily be automated with triggers.

    Finally, if you're using an ORM, this can be really easy to manage. The ORM can take care of inserting the values, updating the ids, and joining the two tables automatically for you.

    Here is how your mutable Customer model would look like:

    class Customer
    {
        private int id;
        private CustomerData currentData;
    
        public Customer(String title, String forename, String surname)
        {
            this.update(title, forename, surname);
        }
    
        public void update(String title, String forename, String surname)
        {
            this.currentData = new CustomerData(this, title, forename, surname);
        }
    
        public String getTitle()
        {
            return this.currentData.getTitle();
        }
    
        public String getForename()
        {
            return this.currentData.getForename();
        }
    
        public String getSurname()
        {
            return this.currentData.getSurname();
        }
    }
    

    And your immutable CustomerData model, that contains only getters:

    class CustomerData
    {
        private int id;
        private Customer customer;
        private String title;
        private String forename;
        private String surname;
    
        public CustomerData(Customer customer, String title, String forename, String surname)
        {
            this.customer = customer;
            this.title    = title;
            this.forename = forename;
            this.surname  = surname;
        }
    
        public String getTitle()
        {
            return this.title;
        }
    
        public String getForename()
        {
            return this.forename;
        }
    
        public String getSurname()
        {
            return this.surname;
        }
    }
    

提交回复
热议问题