web-dev-qa-db-ja.com

MySQLは最新の行のみに参加しますか?

Customer_id、電子メール、および参照を格納するテーブルcustomerがあります。顧客に対して行われた変更の履歴レコードを保存する追加のテーブルcustomer_dataがあります。つまり、変更が行われたときに新しい行が挿入されます。

テーブルに顧客情報を表示するには、2つのテーブルを結合する必要がありますが、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

さらに、このようにCONCATをLIKEとともに使用できると考えるのは正しいですか?

(INNER JOINは、使用するJOINの間違ったタイプである可能性があることを感謝します。実際、異なるJOINの違いがわからないので、今から調べます!)

75
bcmcfc

次のことを試してください。

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;

JOININNER 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)
120
Daniel Vassallo

大量のクエリを使用している場合は、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
   )
75
Danny Coulombe

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
10
Thomas

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では動作します。

9
payne8

私はこの質問が古いことを知っていますが、長年にわたって多くの注目を集めており、同様の場合に誰かを助ける概念が欠けていると思います。完全を期すためにここに追加します。

元のデータベーススキーマを変更できない場合は、多くの適切な回答が提供されており、問題をうまく解決しています。

canの場合、スキーマを変更する場合、customerテーブルに最新のcustomer_dataidを保持するフィールドを追加することをお勧めします。この顧客の記録:

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の更新、および2つのテーブルの自動結合を自動的に行います。

可変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;
    }
}
3
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%' 

c.customer_idをc.idに変更する必要があると思います

それ以外の場合は、テーブル構造を更新します

2
Pramendra Gupta

これもできます

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

実際のデータを "customer_data"テーブルに記録することをお勧めします。このデータを使用すると、「customer_data」テーブルからすべてのデータを自由に選択できます。

0
Burçin

これは役立つかもしれません

mysqlテーブルから最新の日付レコードのセットを選択する方法

サブクエリを使用して最新のレコードを取得し、顧客に参加できます。

0
Jaydee