-1

概要

多数の顧客を選択し、他のテーブルから最新のデータを結合する半結合 (っぽい) クエリを探しています。

後で、クエリの最後に条件を直接追加したいと思います。WHERE c.id IN (1,2,3)

問題

私の知る限り、私の要件は次のことを除外していますGROUP BY

SELECT * FROM customer c
LEFT JOIN customer_address ca ON ca.customer_id = c.id
GROUP BY c.id
# PROBLEM: Cannot append conditions *after* GROUP BY!

ほとんどのサブクエリ ベースの試行では、私の問題は同じです。

追加の課題として、セミ結合を厳密に使用することはできません。これは、同じテーブルからの少なくとも 2 種類の電話番号 (携帯電話と固定電話) を許可するためです。そのため、電話番号テーブルから、顧客ごとに複数のレコードを結合している可能性があります。つまり、これは準結合ではありません。以下の私の現在の解決策はこれを示しています。

質問

  • 一番下のEXPLAIN結果は、私にはパフォーマンスが良いように見えます。私は正しいですか?各サブクエリは 1 回だけ実行されますか? 更新:DEPENDENT SUBQUERYは、外側のクエリの行ごとに 1 回実行されるようです。これを回避できれば最高です。
  • 私がやっていることに対するより良い解決策はありますか?

DDL

DROP TABLE IF EXISTS customer;

CREATE TABLE `customer` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`)
);

DROP TABLE IF EXISTS customer_address;

CREATE TABLE `customer_address` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` bigint(20) unsigned NOT NULL,
  `street` varchar(85) DEFAULT NULL,
  `house_number` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
  );

DROP TABLE IF EXISTS customer_phone; 
CREATE TABLE `customer_phone` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `customer_id` bigint(20) unsigned NOT NULL,
  `phone` varchar(32) DEFAULT NULL,
  `type` tinyint(3) unsigned NOT NULL COMMENT '1=mobile,2=landline',
  PRIMARY KEY (`id`)
  );

insert ignore customer values (1);
insert ignore customer_address values (1, 1, "OldStreet", 1),(2, 1, "NewStreet", 1);
insert ignore customer_phone values (1, 1, "12345-M", 1),(2, 1, "12345-L-Old", 2),(3, 1, "12345-L-New", 2);

SELECT * FROM customer;
+----+
| id |
+----+
|  1 |
+----+

SELECT * FROM customer_address;
+----+-------------+-----------+--------------+
| id | customer_id | street    | house_number |
+----+-------------+-----------+--------------+
|  1 |           1 | OldStreet |            1 |
|  2 |           1 | NewStreet |            1 |
+----+-------------+-----------+--------------+

SELECT * FROM customer_phone;
+----+-------------+-------------+------+
| id | customer_id | phone       | type |
+----+-------------+-------------+------+
|  1 |           1 | 12345-M     |    1 |
|  2 |           1 | 12345-L-Old |    2 |
|  3 |           1 | 12345-L-New |    2 |
+----+-------------+-------------+------+

これまでの解決策

SELECT *
FROM customer c

# Join the most recent address
LEFT JOIN customer_address ca ON ca.id = (SELECT MAX(ca.id) FROM customer_address ca WHERE ca.customer_id = c.id)

# Join the most recent mobile phone number
LEFT JOIN customer_phone cphm ON cphm.id = (SELECT MAX(cphm.id) FROM customer_phone cphm WHERE cphm.customer_id = c.id AND cphm.`type` = 1)

# Join the most recent landline phone number
LEFT JOIN customer_phone cphl ON cphl.id = (SELECT MAX(cphl.id) FROM customer_phone cphl WHERE cphl.customer_id = c.id AND cphl.`type` = 2)

# Yay conditions appended at the end
WHERE c.id IN (1,2,3)

フィドル

このフィドルは、指定されたソリューションを使用して適切な結果セットを提供します。上記の私の質問を参照してください。

http://sqlfiddle.com/#!9/98c57/3

4

1 に答える 1