【发布时间】:2017-05-30 13:56:18
【问题描述】:
我有 3 张桌子。
companies
- id
- name
- user_id
departments
- id
- name
- user_id
- company_id
invoices
- id
- department_id
- price
- created_at
出于性能目的,我正在尝试在 1 个大型 mysql 查询中获取“仪表板”屏幕所需的所有数据。值得一提的是,invoices 表有大约 700k 条记录,并且大小只会不断增加。
所以我需要获取所有用户的公司、部门以及每个部门的最后 2 张发票(每个 id 的 2 个最高日期)。
现在我对前 2 个没有问题,我可以很容易地做到这一点,例如:
SELECT companies.id as company_id, companies.name as company_name, departments.id as department_id, departments.name as department_name
FROM companies
LEFT JOIN departments
ON companies.id = departments.company_id
WHERE companies.user_id = 1
我只是在努力获取每个部门的最新 2 张发票。在同一个查询中执行此操作的最佳方法是什么?
这是请求的数据,和SQL Fiddle 相同。
CREATE TABLE `companies` (
`id` int(10) UNSIGNED NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `departments` (
`id` int(10) UNSIGNED NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`user_id` int(11) NOT NULL,
`company_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `invoices` (
`id` int(10) UNSIGNED NOT NULL,
`price` decimal(6,2) NOT NULL,
`created_at` timestamp NULL DEFAULT NULL,
`department_id` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `companies`
ADD PRIMARY KEY (`id`);
ALTER TABLE `departments`
ADD PRIMARY KEY (`id`);
ALTER TABLE `invoices`
ADD PRIMARY KEY (`id`);
ALTER TABLE `companies`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
ALTER TABLE `departments`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
ALTER TABLE `invoices`
MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=1;
INSERT INTO companies
(`name`, `user_id`)
VALUES
('Google', 1),
('Apple', 1),
('IBM', 1)
;
INSERT INTO departments
(`name`, `user_id`, `company_id`)
VALUES
('Billing', 1, 1),
('Support', 1, 1),
('Tech', 1, 1),
('Billing Dept', 1, 2),
('Support Dept', 1, 2),
('Tech Dept', 1, 2),
('HR', 1, 3),
('IT', 1, 3),
('Executive', 1, 3)
;
INSERT INTO invoices
(`price`, `created_at`, `department_id`)
VALUES
(155.23, '2016-04-07 14:39:29', 1),
(123.23, '2016-04-07 14:40:26', 1),
(150.50, '2016-04-07 14:40:30', 1),
(123.23, '2016-04-07 14:41:38', 1),
(432.65, '2016-04-07 14:44:15', 1),
(323.23, '2016-04-07 14:44:22', 2),
(541.43, '2016-04-07 14:44:33', 2),
(1232.23, '2016-04-07 14:44:36', 2),
(433.42, '2016-04-07 14:44:37', 2),
(1232.43, '2016-04-07 14:44:39', 2),
(850.40, '2016-04-07 14:44:46', 3),
(133.32, '2016-04-07 14:45:11', 3),
(12.43, '2016-04-07 14:45:15', 3),
(154.23, '2016-04-07 14:45:25', 3),
(132.43, '2016-04-07 14:46:01', 3),
(859.55, '2016-04-07 14:53:11', 4),
(123.43, '2016-04-07 14:53:45', 4),
(433.33, '2016-04-07 14:54:14', 4),
(545.12, '2016-04-07 14:54:54', 4),
(949.99, '2016-04-07 14:55:10', 4),
(1112.32, '2016-04-07 14:53:40', 5),
(132.32, '2016-04-07 14:53:44', 5),
(42.43, '2016-04-07 14:53:48', 5),
(545.34, '2016-04-07 14:53:56', 5),
(2343.32, '2016-04-07 14:54:05', 5),
(3432.43, '2016-04-07 14:54:02', 6),
(231.32, '2016-04-07 14:54:22', 6),
(1242.33, '2016-04-07 14:54:54', 6),
(232.32, '2016-04-07 14:55:12', 6),
(43.12, '2016-04-07 14:55:23', 6),
(4343.23, '2016-04-07 14:55:24', 7),
(1123.32, '2016-04-07 14:55:31', 7),
(4343.32, '2016-04-07 14:55:56', 7),
(354.23, '2016-04-07 14:56:04', 7),
(867.76, '2016-04-07 14:56:12', 7),
(45.76, '2016-04-07 14:55:54', 8),
(756.65, '2016-04-07 14:56:08', 8),
(153.74, '2016-04-07 14:56:14', 8),
(534.86, '2016-04-07 14:56:23', 8),
(867.65, '2016-04-07 14:56:55', 8),
(433.56, '2016-04-07 14:56:32', 9),
(1423.43, '2016-04-07 14:56:54', 9),
(342.56, '2016-04-07 14:57:11', 9),
(343.75, '2016-04-07 14:57:23', 9),
(1232.43, '2016-04-07 14:57:34', 9)
;
这是想要的结果。
company_id| company_name| department_id | department_name | invoice_price | invoice_created_at
1| Google | 1 | Billing | 123.23 | 2016-04-07 14:41:38 |
1| Google | 1 | Billing | 432.65 | 2016-04-07 14:44:15 |
1| Google | 2 | Support | 433.42 | 2016-04-07 14:44:37 |
1| Google | 2 | Support | 1232.43 | 2016-04-07 14:44:39 |
1| Google | 3 | Tech | 154.23 | 2016-04-07 14:45:25 |
1| Google | 3 | Tech | 132.43 | 2016-04-07 14:46:01 |
2| Apple | 4 | Billing Dept | 545.12 | 2016-04-07 14:54:54 |
2| Apple | 4 | Billing Dept | 949.99 | 2016-04-07 14:55:10 |
2| Apple | 5 | Support Dept | 545.34 | 2016-04-07 14:53:56 |
2| Apple | 5 | Support Dept | 2343.32 | 2016-04-07 14:54:05 |
2| Apple | 6 | Tech Dept | 232.32 | 2016-04-07 14:55:12 |
2| Apple | 6 | Tech Dept | 43.12 | 2016-04-07 14:55:23 |
3| IBM | 7 | HR | 354.23 | 2016-04-07 14:56:04 |
3| IBM | 7 | HR | 867.76 | 2016-04-07 14:56:12 |
3| IBM | 8 | IT | 534.86 | 2016-04-07 14:56:23 |
3| IBM | 8 | IT | 867.65 | 2016-04-07 14:56:55 |
3| IBM | 9 | Executive | 343.75 | 2016-04-07 14:57:23 |
3| IBM | 9 | Executive | 1232.43 | 2016-04-07 14:57:34 |
【问题讨论】:
-
"现在我的前 2 个没有问题..." - 您的查询没有这样做。
-
@Strawberry 谢谢。我添加了 SQL 小提琴数据。
-
@PaulSpiegel 不知道你为什么这么认为。请参阅我发布的 SQL 小提琴链接,该链接显示该查询按预期执行。
-
@zen “前两张没有问题” - 抱歉,我以为您指的是前两张发票。但现在我猜你的意思是前两个表。
-
@Strawberry 我添加了以逗号分隔的所需结果。希望这有助于澄清问题。
标签: php mysql greatest-n-per-group