MySQL присоединяется только к самой последней строке?
У меня есть таблица customer, которая хранит customer_id, электронную почту и ссылку. Существует дополнительная таблица customer_data, в которой хранится историческая запись изменений, внесенных в клиента, т. е. когда есть изменение, вставляется новая строка.
для отображения информации о клиенте в таблице необходимо объединить две таблицы, однако к таблице customer следует присоединить только самую последнюю строку из customer_data.
он получает немного больше сложность в том, что запрос разбивается на страницы, поэтому имеет ограничение и смещение.
Как я могу сделать это с MySQL? Я думаю, что я хочу поставить отличного там где-то...
запрос в данный момент выглядит так -
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
кроме того, я прав, думая, что могу использовать CONCAT с подобным образом?
(Я понимаю, что внутреннее соединение может быть неправильным типом соединения для использования. Я на самом деле понятия не имею, в чем разница между различными присоединяется. Я собираюсь разобраться в этом сейчас!)
9 ответов:
вы можете попробовать следующее:
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;
обратите внимание, что a
JOIN
- это просто синоним дляINNER JOIN
.тест:
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');
результат (запрос без
LIMIT
и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)
Если вы работаете с тяжелыми запросами, вам лучше переместить запрос на последнюю строку в предложении where. Это намного быстрее и выглядит чище.
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 )
предполагая колонку автоинкремента в
customer_data
называетсяId
, вы можете сделать: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
для тех, кто должен работать с более старой версией MySQL (pre-5.0 ish), вы не можете выполнять подзапросы для этого типа запроса. Вот решение, которое я смог сделать, и оно, казалось, отлично работает.
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;
по существу это поиск максимального идентификатора вашей таблицы данных, соединяющей его с клиентом, а затем присоединение таблицы данных к максимальному идентификатору найдено. Причина этого заключается в том, что выбор max группы не гарантирует, что остальные данные совпадают с идентификатором, если только вы присоединяете его обратно к себе.
Я не тестировал это на более новых версиях MySQL, но он работает на 4.0.30.
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%'
Я думаю, что вам нужно изменить c. customer_id to c.id
еще обновить структуру таблицы
я знаю, что этот вопрос стар, но он получил много внимания на протяжении многих лет, и я думаю, что ему не хватает концепции, которая может помочь кому-то в подобном случае. Я добавляю его здесь для полноты картины.
если вы не можете изменить исходную схему базы данных, то много хороших ответов были предоставлены и решить эту проблему просто отлично.
если вы можете, однако, изменить вашу схему, я бы посоветовал добавить поле в
customer
таблица, которая содержит элементid
последниеcustomer_data
запись для этого клиента: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 );
запрос клиентов
запрос-это так легко и быстро, как это может быть:
SELECT c.*, d.title, d.forename, d.surname FROM customer c INNER JOIN customer_data d on d.id = c.current_data_id WHERE ...;
недостатком является дополнительная сложность при создании или обновлении клиента.
обновление клиента
всякий раз, когда вы хотите обновить клиента, вы вставляете новую запись в
customer_data
таблица, и обновить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;
создание клиент
создание клиента-это всего лишь вопрос вставки
customer
запись, затем запуск тех же операторов: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;
подводя итоги
дополнительная сложность для создания / обновления клиента может быть страшной, но ее можно легко автоматизировать с помощью триггеров.
наконец, если вы используете ORM, это может быть очень легко управлять. ORM может позаботиться о вставке значений, обновлении идентификаторов и соединении двух таблиц автоматически для вас.
вот как ваш Мутабельный
Customer
модель будет выглядеть так: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(); } }
и ваш неизменный
CustomerData
модель, которая содержит только геттеры: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; } }
Это хорошая идея, что регистрация фактических данных в "customer_data" таблица. С помощью этих данных вы можете выбрать все данные из таблицы "customer_data", как вы хотите.
Это может помочь
как выбрать самый последний набор датированных записей из таблицы mysql
вы можете использовать подзапрос, чтобы получить самые последние записи, а затем присоединиться к своему клиенту.
вы также можете сделать это
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;