wake-up-neo.com

MySQL JOIN nur die letzte Zeile?

Ich habe einen Tischkunden, der eine customer_id, eine E-Mail und eine Referenz speichert. Es gibt eine zusätzliche Tabelle customer_data, in der ein historischer Datensatz der am Kunden vorgenommenen Änderungen gespeichert wird, d. H. Wenn eine Änderung vorgenommen wurde, wird eine neue Zeile eingefügt.

Um die Kundeninformationen in einer Tabelle anzuzeigen, müssen die beiden Tabellen verknüpft werden. Es sollte jedoch nur die letzte Zeile aus customer_data mit der Kundentabelle verbunden werden.

Es wird etwas komplizierter, da die Abfrage paginiert ist, also ein Limit und ein Offset hat.

Wie kann ich das mit MySQL machen? Ich glaube, ich möchte irgendwo ein DISTINCT einsetzen ...

Die Abfrage auf die Minute ist wie folgt:

SELECT *, CONCAT(title,' ',forename,' ',surname) AS name
FROM customer c
INNER JOIN customer_data d on c.customer_id=d.customer_id
WHERE name LIKE '%Smith%' LIMIT 10, 20

Bin ich außerdem der Meinung, dass ich CONCAT mit LIKE auf diese Weise verwenden kann?

(Ich schätze, dass INNER JOIN die falsche Art von JOIN ist. Ich habe keine Ahnung, was der Unterschied zwischen den verschiedenen JOINs ist. Ich werde das jetzt untersuchen!)

64
bcmcfc

Möglicherweise möchten Sie Folgendes versuchen:

SELECT    CONCAT(title, ' ', forename, ' ', surname) AS name
FROM      customer c
JOIN      (
              SELECT    MAX(id) max_id, customer_id 
              FROM      customer_data 
              GROUP BY  customer_id
          ) c_max ON (c_max.customer_id = c.customer_id)
JOIN      customer_data cd ON (cd.id = c_max.max_id)
WHERE     CONCAT(title, ' ', forename, ' ', surname) LIKE '%Smith%' 
LIMIT     10, 20;

Beachten Sie, dass eine JOIN nur ein Synonym für INNER JOIN ist.

Testfall:

CREATE TABLE customer (customer_id int);
CREATE TABLE customer_data (
   id int, 
   customer_id int, 
   title varchar(10),
   forename varchar(10),
   surname varchar(10)
);

INSERT INTO customer VALUES (1);
INSERT INTO customer VALUES (2);
INSERT INTO customer VALUES (3);

INSERT INTO customer_data VALUES (1, 1, 'Mr', 'Bobby', 'Smith');
INSERT INTO customer_data VALUES (2, 1, 'Mr', 'Bob', 'Smith');
INSERT INTO customer_data VALUES (3, 2, 'Mr', 'Jane', 'Green');
INSERT INTO customer_data VALUES (4, 2, 'Miss', 'Jane', 'Green');
INSERT INTO customer_data VALUES (5, 3, 'Dr', 'Jack', 'Black');

Ergebnis (Abfrage ohne LIMIT und WHERE):

SELECT    CONCAT(title, ' ', forename, ' ', surname) AS name
FROM      customer c
JOIN      (
              SELECT    MAX(id) max_id, customer_id 
              FROM      customer_data 
              GROUP BY  customer_id
          ) c_max ON (c_max.customer_id = c.customer_id)
JOIN      customer_data cd ON (cd.id = c_max.max_id);

+-----------------+
| name            |
+-----------------+
| Mr Bob Smith    |
| Miss Jane Green |
| Dr Jack Black   |
+-----------------+
3 rows in set (0.00 sec)
105
Daniel Vassallo

Wenn Sie mit umfangreichen Abfragen arbeiten, verschieben Sie die Anforderung für die letzte Zeile in der where-Klausel. Es ist viel schneller und sieht sauberer aus.

SELECT c.*,
FROM client AS c
LEFT JOIN client_calling_history AS cch ON cch.client_id = c.client_id
WHERE
   cch.cchid = (
      SELECT MAX(cchid)
      FROM client_calling_history
      WHERE client_id = c.client_id AND cal_event_id = c.cal_event_id
   )
62
Danny Coulombe

Unter der Annahme, dass die Autoincrement-Spalte in customer_data den Namen Id hat, können Sie Folgendes tun:

SELECT CONCAT(title,' ',forename,' ',surname) AS name *
FROM customer c
    INNER JOIN customer_data d 
        ON c.customer_id=d.customer_id
WHERE name LIKE '%Smith%'
    AND d.ID = (
                Select Max(D2.Id)
                From customer_data As D2
                Where D2.customer_id = D.customer_id
                )
LIMIT 10, 20
10
Thomas

Für jeden, der mit einer älteren Version von MySQL (vor Version 5.0 ish) arbeiten muss, können Sie für diesen Abfragetyp keine Unterabfragen ausführen. Hier ist die Lösung, die ich konnte, und es schien großartig zu funktionieren.

SELECT MAX(d.id), d2.*, CONCAT(title,' ',forename,' ',surname) AS name
FROM customer AS c 
LEFT JOIN customer_data as d ON c.customer_id=d.customer_id 
LEFT JOIN customer_data as d2 ON d.id=d2.id
WHERE CONCAT(title, ' ', forename, ' ', surname) LIKE '%Smith%'
GROUP BY c.customer_id LIMIT 10, 20;

Im Wesentlichen ist dies die Ermittlung der maximalen ID Ihrer Datentabelle, die sie mit dem Kunden verbindet, und dann die Datentabelle mit der gefundenen maximalen ID. Der Grund dafür ist, dass die Auswahl des Maximums einer Gruppe nicht garantiert, dass die restlichen Daten mit der ID übereinstimmen, es sei denn, Sie fügen sie wieder zusammen.

Ich habe dies nicht mit neueren Versionen von MySQL getestet, aber es funktioniert mit 4.0.30.

9
payne8

Ich weiß, dass diese Frage alt ist, aber sie hat im Laufe der Jahre viel Aufmerksamkeit auf sich gezogen und ich denke, es fehlt ein Konzept, das jemandem in einem ähnlichen Fall helfen könnte. Ich füge es hier der Vollständigkeit halber hinzu.

Wenn Sie Ihr ursprüngliches Datenbankschema nicht ändern können, wurden viele gute Antworten bereitgestellt, die das Problem gut lösen.

Wenn Sie jedoch can Ihr Schema ändern, würde ich empfehlen, ein Feld in Ihrer customer-Tabelle hinzuzufügen, das die id des neuesten customer_data-Datensatzes für diesen Kunden enthält:

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
);

Kunden abfragen

Das Abfragen ist so einfach und schnell wie möglich:

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

Der Nachteil ist die zusätzliche Komplexität beim Erstellen oder Aktualisieren eines Kunden.

Einen Kunden aktualisieren

Wenn Sie einen Kunden aktualisieren möchten, fügen Sie einen neuen Datensatz in die Tabelle customer_data ein und aktualisieren den Datensatz customer.

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;

Einen Kunden anlegen

Beim Erstellen eines Kunden müssen Sie lediglich den Eintrag customer einfügen und dann die gleichen Anweisungen ausführen:

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;

Einpacken

Die zusätzliche Komplexität für das Erstellen/Aktualisieren eines Kunden ist möglicherweise furchterregend, kann jedoch leicht mit Triggern automatisiert werden.

Wenn Sie ein ORM verwenden, kann dies sehr einfach zu verwalten sein. Der ORM kann für das Einfügen der Werte, das Aktualisieren der IDs und das automatische Verknüpfen der beiden Tabellen sorgen.

So würde Ihr veränderliches Customer-Modell aussehen:

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();
    }
}

Und Ihr unveränderliches CustomerData-Modell, das nur Getter enthält:

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;
    }
}
2
Benjamin
SELECT CONCAT(title,' ',forename,' ',surname) AS name * FROM customer c 
INNER JOIN customer_data d on c.id=d.customer_id WHERE name LIKE '%Smith%' 

ich denke, Sie müssen c.customer_id in c.id ändern

sonst aktualisieren Sie die Tabellenstruktur

2
Pramendra Gupta

Sie können das auch tun

SELECT    CONCAT(title, ' ', forename, ' ', surname) AS name
FROM      customer c
LEFT JOIN  (
              SELECT * FROM  customer_data ORDER BY id DESC
          ) customer_data ON (customer_data.customer_id = c.customer_id)
GROUP BY  c.customer_id          
WHERE     CONCAT(title, ' ', forename, ' ', surname) LIKE '%Smith%' 
LIMIT     10, 20;
0
Ajay Kumar

Es ist eine gute Idee, die tatsächlichen Daten in der Tabelle " customer_data " zu protokollieren. Mit diesen Daten können Sie nach Belieben alle Daten aus der Tabelle "customer_data" auswählen.

0
Burçin

Das könnte helfen

So wählen Sie den neuesten Satz datierter Datensätze aus einer MySQL-Tabelle aus

Sie können eine Unterabfrage verwenden, um die neuesten Datensätze abzurufen und sich dann Ihrem Kunden anzuschließen.

0
Jaydee