我有两张表,反映了有关递交给客户的卡的数据。
第一个表是所有客户的列表。客户有一张卡号,这是第一张交给客户的卡。
card:
+----------+-------------+
| card_id | Name, etc |
+----------+-------------+
| 123123 | First Client|
| 123124 | 2nd Client|
+----------+-------------+
第二个表是历史文件,其中包含card_id作为外键。 更换卡(例如,丢失,被盗,过期)时,卡表不会更改,但会在历史文件中创建一个条目。
card_history:
+----------+-------------+--------------+----------------+
| card_id | new_card_id | Date_created | date_replaced |
+----------+-------------+--------------+----------------+
| 123123 | 123123 | 2010-01-01 | 0000-00-00 |
| 123123 | 123789 | 0000-00-00 | 2010-01-31 |
| 123123 | 123790 | 0000-00-00 | 2010-02-15 |
+----------+-------------+--------------+----------------+
在这里,您可以看到2010-01-01上出现了一张新卡,并在2010-01-31和2010-02-15进行了两次更换。
我需要生成一个如下所示的报告(使用mysql)。
Name, old_card, new_card, date_issued
------------------------------------------------
"First Client", 123123, 123790, 2010-02-15
我目前的查询太慢了。
我尝试了两种方法:
0.1。使用连接创建单个查询
SELECT ...
FROM card
LEFT JOIN card_history ON card.card_id = card_history.card_id
AND ( select ....)
但我似乎无法使子查询正确。
0.2。创建了一个视图
CREATE VIEW v1 as
SELECT MAX(GREATER(Date_created, date_replaced) as date_issued
FROM card_history
GROUP BY card_id
视图有效,但速度非常慢(每次查找约40秒)。这两个表都很大,有大约200万条记录。我在card_ids上有索引。
如何构建查询以便我可以有效地提取所需的数据?
更新
首先,我没有提到这些卡不是以任何顺序发行的,它们是随机发放的,这使得解决方案提供了方便,但对我的情况不正确。
其次,我对派生表的奇迹感到敬畏,并拥有当前查询,它导出两个表之间的连接,并尝试获取我们寻找的记录(card_history表中最后更新的条目)。 / p>
SELECT * FROM
(
SELECT card.card_id, card.name,
card_history.new_card_id,
card_history.date_created, card_history.date_replaced, GREATEST(card_history.date_created, card_history.date_replaced) AS last_date
FROM card
LEFT JOIN card_history ON card.card_id = card_history.card_id
ORDER BY last_date DESC
) AS B
;
但是,我怀疑我的查询是随机选择派生表行。
我需要的是提取new_card_id和发布或替换的最后日期。
我的查询是否会删除它?
答案 0 :(得分:1)
use test
DROP TABLE IF EXISTS card;
DROP TABLE IF EXISTS card_history;
CREATE TABLE card ( card_id INT NOT NULL PRIMARY KEY,name VARCHAR(255) );
CREATE TABLE card_history
(card_id INT NOT NULL,new_card_id INT NOT NULL,
date_created date,date_replaced date,
PRIMARY KEY (card_id,new_card_id),
KEY (card_id,date_replaced));
INSERT INTO card VALUES (123123,'First Client'),(123124,'2ndClient');
INSERT INTO card_history VALUES
(123123,123123,'2010-01-01','0000-00-00'),
(123123,123789,'0000-00-00','2010-01-31'),
(123123,123790,'0000-00-00','2010-02-15');
SELECT AA.name,AA.card_id old_card,
(SELECT MAX(new_card_id)
FROM card_history BB
WHERE BB.card_id=AA.card_id) new_card,
(SELECT MAX(GREATEST(date_created,date_replaced))
FROM card_history BB
WHERE BB.card_id=AA.card_id) date_issued
FROM (SELECT A.name,B.card_id
FROM card A
INNER JOIN card_history B USING (card_id)
WHERE B.card_id=B.new_card_id) AA;
+--------------+----------+----------+-------------+
| name | old_card | new_card | date_issued |
+--------------+----------+----------+-------------+
| First Client | 123123 | 123790 | 2010-02-15 |
+--------------+----------+----------+-------------+
如果要排除没有发出新卡的行,请执行以下操作:
SELECT *
FROM
(SELECT AA.name,AA.card_id old_card,
(SELECT MAX(new_card_id)
FROM card_history BB
WHERE BB.card_id=AA.card_id) new_card,
(SELECT MAX(GREATEST(date_created,date_replaced))
FROM card_history BB
WHERE BB.card_id=AA.card_id) date_issued
FROM (
SELECT A.name,B.card_id
FROM card A
INNER JOIN card_history B USING (card_id)
WHERE B.card_id=B.new_card_id) AA
) AAA
WHERE old_card <> new_card;
它对我有用!!!试一试!!!
我查看了我的EXPLAIN计划,我不喜欢我所看到的。
请确保card_history的主键是(card_id,new_card_id)
我还添加了索引(card_id,date_replaced)
试试这个;这有一个更好的EXPLAIN计划。
SELECT AA.name,AA.card_id old_card,
(SELECT MAX(new_card_id)
FROM card_history BB
WHERE BB.card_id=AA.card_id) new_card,
(SELECT MAX(date_replaced)
FROM card_history BB
WHERE BB.card_id=AA.card_id) date_issued
FROM (
SELECT A.name,B.card_id
FROM card A
INNER JOIN card_history B USING (card_id)
WHERE B.card_id=B.new_card_id) AA;
如果您希望报告显示新卡片,请坚持我的第一个查询。
玩得开心!!!