[mysql] MySQL은 가장 최근 행에만 가입 하시겠습니까?
customer_id, 이메일 및 참조를 저장하는 테이블 customer가 있습니다. 고객에 대한 변경 내역 기록을 저장하는 추가 테이블 customer_data가 있습니다. 즉, 변경 사항이있을 때 새 행이 삽입됩니다.
테이블에 고객 정보를 표시하려면 두 테이블을 조인해야하지만 customer_data의 가장 최근 행만 고객 테이블에 조인해야합니다.
쿼리에 페이지가 매겨져 있으므로 제한과 오프셋이 있다는 점에서 조금 더 복잡해집니다.
MySQL로 어떻게 할 수 있습니까? 어딘가에 DISTINCT를 넣고 싶은 것 같아요 …
순간의 쿼리는 다음과 같습니다.
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
추가로, 이런 식으로 LIKE와 함께 CONCAT을 사용할 수 있다고 생각하는 것이 맞습니까?
(INNER JOIN이 사용하기에 잘못된 유형의 JOIN 일 수 있다는 점에 감사드립니다. 실제로 서로 다른 JOIN의 차이점이 무엇인지 전혀 알 수 없습니다. 지금 살펴 보겠습니다!)
답변
다음을 시도해 볼 수 있습니다.
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
)
답변
의 autoincrement 열의 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 (5.0 이전 버전)으로 작업해야하는 사람은 이러한 유형의 쿼리에 대해 하위 쿼리를 수행 할 수 없습니다. 여기 내가 할 수 있었던 해결책이 있고 잘 작동하는 것 같았습니다.
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;
본질적으로 이것은 고객과 결합하는 데이터 테이블의 최대 ID를 찾은 다음 발견 된 최대 ID에 데이터 테이블을 결합하는 것입니다. 그 이유는 그룹의 최대 값을 선택해도 나머지 데이터가 ID와 일치하는 것을 보장하지 않기 때문입니다.
나는 이것을 MySQL의 최신 버전에서 테스트하지 않았지만 4.0.30에서 작동합니다.
답변
이 질문이 오래되었다는 것을 알고 있지만 수년에 걸쳐 많은 관심을 받고 있으며 비슷한 경우에 누군가를 도울 수있는 개념이 누락 된 것 같습니다. 완전성을 위해 여기에 추가하겠습니다.
원래 데이터베이스 스키마를 수정할 수 없다면 많은 좋은 답변이 제공되었으며 문제를 잘 해결했습니다.
당신이 경우 수 있습니다 , 그러나, 스키마를 수정, 당신의 필드를 추가 할 권합니다 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은 값 삽입, ID 업데이트 및 자동으로 두 테이블 결합을 처리 할 수 있습니다.
변경 가능한 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
getter 만 포함하는 변경 불가능한 모델 :
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;
}
}
답변
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를 c.id로 변경해야한다고 생각합니다.
그렇지 않으면 테이블 구조를 업데이트합니다.
답변
당신은 또한 이것을 할 수 있습니다
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;