无法在 SQL 中将日期放在列中,将指标放在另一个列中

Posted

技术标签:

【中文标题】无法在 SQL 中将日期放在列中,将指标放在另一个列中【英文标题】:Unable to put dates in a column and metric in another in SQL 【发布时间】:2020-11-21 21:23:37 【问题描述】:

问题:对于给定的第 t 天,我需要为卖家 ID“123”创建一个 61 天的准时交货 (OTD) 指标。 OTD 是按时交付包裹的比率 对于在 t 之前 30 天内创建的包。 我们不仅想知道今天的OTD,而且我们想知道OTD 过去 60 天内的每个日期。

CREATE TABLE `packages` (
  `id` int NOT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `seller_id` int DEFAULT NULL,
  `promise_date` date DEFAULT NULL,
  `delivered_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`)
);
INSERT INTO `packages` (`id`, `created_at`, `seller_id`, `promise_date`, `delivered_at`) VALUES
('1', '2020-04-15 06:26:28', '246', '2020-04-20', '2020-04-20 07:47:07'),
('2', '2020-05-02 06:19:13', '123', '2020-05-06', '2020-05-07 07:01:26'),
('3', '2020-07-05 08:47:17', '789', '2020-07-08', '2020-07-09 08:22:08'),
('4', '2020-03-25 08:12:35', '234', '2020-03-30', '2020-03-30 08:49:50'),
('5', '2020-07-01 07:51:33', '789', '2020-07-06', '2020-07-06 08:34:48'),
('6', '2020-03-01 08:11:31', '123', '2020-03-04', '2020-03-04 06:00:14'),
('7', '2020-05-20 07:38:14', '246', '2020-05-25', '2020-05-25 08:13:51'),
('8', '2020-04-14 07:30:19', '123', '2020-04-17', '2020-04-17 07:46:55'),
('9', '2020-02-10 08:53:00', '234', '2020-02-13', '2020-02-14 06:45:57'),
('10', '2020-01-21 07:14:56', '246', '2020-01-24', '2020-01-25 08:03:04'),
('11', '2020-07-03 08:05:11', '123', '2020-07-08', '2020-07-09 08:30:56'),
('12', '2020-05-09 06:18:31', '789', '2020-05-13', '2020-05-13 08:38:55'),
('13', '2020-02-13 08:11:10', '123', '2020-02-18', '2020-02-18 07:48:52'),
('14', '2020-04-28 08:25:28', '789', '2020-05-01', '2020-05-02 06:06:32'),
('15', '2020-06-02 07:28:52', '234', '2020-06-05', '2020-06-06 07:29:43'),
('16', '2020-05-04 08:39:33', '123', '2020-05-07', '2020-05-08 06:33:14'),
('17', '2020-07-26 08:18:30', '789', '2020-07-29', '2020-07-30 07:28:53'),
('18', '2020-02-25 08:37:42', '234', '2020-02-28', '2020-02-29 06:05:23'),
('19', '2020-02-03 06:55:39', '234', '2020-02-06', '2020-02-07 07:18:28'),
('20', '2020-03-07 08:20:44', '246', '2020-03-11', '2020-03-11 08:11:45'),
('21', '2020-03-11 07:19:47', '789', '2020-03-16', '2020-03-16 06:55:46'),
('22', '2020-06-24 08:18:56', '789', '2020-06-29', '2020-06-29 08:47:59'),
('23', '2020-02-25 07:24:19', '123', '2020-02-28', '2020-02-28 06:54:57'),
('24', '2020-07-12 07:51:52', '789', '2020-07-15', '2020-07-16 07:36:21'),
('25', '2020-01-26 07:44:59', '234', '2020-01-29', '2020-01-29 08:52:24'),
('26', '2020-02-07 06:09:24', '246', '2020-02-12', '2020-02-13 08:16:37'),
('27', '2020-03-11 08:34:57', '123', '2020-03-16', '2020-03-17 08:33:47'),
('28', '2020-02-24 08:15:41', '789', '2020-02-27', '2020-02-27 06:19:59'),
('29', '2020-02-02 06:45:36', '123', '2020-02-05', '2020-02-06 06:22:25'),
('30', '2020-02-10 06:51:48', '123', '2020-02-13', '2020-02-13 06:45:07'),
('31', '2020-03-27 07:11:58', '789', '2020-04-01', '2020-04-02 08:55:56'),
('32', '2020-05-31 07:10:05', '246', '2020-06-03', '2020-06-03 08:56:47'),
('33', '2020-06-28 06:14:19', '789', '2020-07-01', '2020-07-02 06:35:18'),
('34', '2020-07-08 08:30:12', '789', '2020-07-13', '2020-07-14 06:06:09'),
('35', '2020-05-13 08:13:34', '123', '2020-05-18', '2020-05-18 08:24:42'),
('36', '2020-04-19 08:13:38', '246', '2020-04-22', '2020-04-22 07:32:14'),
('37', '2020-03-02 06:57:32', '234', '2020-03-05', '2020-03-05 07:16:05'),
('38', '2020-05-22 08:49:51', '246', '2020-05-27', '2020-05-27 06:47:41'),
('39', '2020-02-27 08:18:26', '123', '2020-03-03', '2020-03-03 06:32:56'),
('40', '2020-02-17 07:10:24', '246', '2020-02-20', '2020-02-21 06:06:26'),
('41', '2020-06-25 08:29:32', '234', '2020-06-30', '2020-06-30 07:37:07'),
('42', '2020-03-02 08:07:57', '234', '2020-03-05', '2020-03-05 08:41:13'),
('43', '2020-06-18 06:44:38', '234', '2020-06-23', '2020-06-23 06:11:26'),
('44', '2020-07-15 08:22:49', '246', '2020-07-20', '2020-07-20 08:34:28'),
('45', '2020-07-07 07:54:10', '123', '2020-07-10', '2020-07-10 07:50:24'),
('46', '2020-07-17 07:43:08', '123', '2020-07-22', '2020-07-22 06:33:22'),
('47', '2020-04-01 08:24:20', '234', '2020-04-06', '2020-04-06 06:12:55'),
('48', '2020-05-14 08:49:10', '123', '2020-05-19', '2020-05-20 06:53:50'),
('49', '2020-06-11 08:20:35', '246', '2020-06-16', '2020-06-16 06:21:10'),
('50', '2020-06-24 06:39:29', '789', '2020-06-29', '2020-06-30 06:03:48'),
('51', '2020-02-29 06:43:01', '246', '2020-03-04', '2020-03-05 07:57:51'),
('52', '2020-07-17 08:23:46', '246', '2020-07-22', '2020-07-22 07:49:01'),
('53', '2020-03-27 07:45:10', '123', '2020-04-01', '2020-04-02 06:43:34'),
('54', '2020-04-28 06:39:55', '246', '2020-05-01', '2020-05-01 08:59:08'),
('55', '2020-05-21 07:16:03', '789', '2020-05-26', '2020-05-26 06:29:53'),
('56', '2020-02-10 08:22:04', '246', '2020-02-13', '2020-02-14 06:24:17'),
('57', '2020-02-02 08:04:26', '234', '2020-02-05', '2020-02-05 08:59:43'),
('58', '2020-03-02 08:21:53', '246', '2020-03-05', '2020-03-06 08:45:36'),
('59', '2020-02-19 08:37:15', '123', '2020-02-24', '2020-02-24 08:24:44'),
('60', '2020-06-16 08:51:24', '234', '2020-06-19', '2020-06-20 08:25:14'),
('61', '2020-07-11 07:37:15', '234', '2020-07-15', '2020-07-15 07:03:13'),
('62', '2020-06-15 07:56:39', '123', '2020-06-18', '2020-06-19 07:11:16'),
('63', '2020-03-06 07:21:52', '123', '2020-03-11', '2020-03-11 07:46:48'),
('64', '2020-06-03 06:43:50', '789', '2020-06-08', '2020-06-09 07:40:17'),
('65', '2020-01-20 06:28:47', '234', '2020-01-23', '2020-01-24 08:34:05'),
('66', '2020-04-02 08:04:41', '123', '2020-04-07', '2020-04-08 08:56:45'),
('67', '2020-03-04 06:05:57', '789', '2020-03-09', '2020-03-10 06:26:56'),
('68', '2020-07-04 06:47:46', '246', '2020-07-08', '2020-07-09 06:53:02'),
('69', '2020-02-25 06:47:09', '246', '2020-02-28', '2020-02-28 07:55:25'),
('70', '2020-02-04 07:17:28', '123', '2020-02-07', '2020-02-07 08:07:54'),
('71', '2020-06-15 07:18:16', '789', '2020-06-18', '2020-06-19 06:02:08'),
('72', '2020-07-09 06:32:34', '234', '2020-07-14', '2020-07-14 08:15:02'),
('73', '2020-05-21 06:12:52', '789', '2020-05-26', '2020-05-27 07:39:20'),
('74', '2020-05-24 06:38:49', '789', '2020-05-27', '2020-05-27 06:51:35'),
('75', '2020-02-27 06:31:02', '123', '2020-03-03', '2020-03-03 08:56:26'),
('76', '2020-07-02 08:55:00', '123', '2020-07-07', '2020-07-07 07:42:16'),
('77', '2020-06-30 06:52:27', '246', '2020-07-03', '2020-07-03 07:43:20'),
('78', '2020-04-25 08:08:14', '246', '2020-04-29', '2020-04-29 07:21:23'),
('79', '2020-06-24 08:34:43', '234', '2020-06-29', '2020-06-30 06:43:59'),
('80', '2020-05-13 08:59:11', '246', '2020-05-18', '2020-05-18 07:19:06'),
('81', '2020-02-21 07:14:16', '789', '2020-02-26', '2020-02-27 07:10:39'),
('82', '2020-06-04 08:43:13', '789', '2020-06-09', '2020-06-09 07:24:28'),
('83', '2020-07-04 07:14:42', '234', '2020-07-08', '2020-07-09 07:45:59'),
('84', '2020-05-24 08:17:00', '246', '2020-05-27', '2020-05-27 06:31:15'),
('85', '2020-03-07 07:43:27', '123', '2020-03-11', '2020-03-12 08:39:45');



create table dates(
fulldate date);

INSERT INTO `dates` (`fulldate`) VALUES
('2020-08-01'),
('2020-07-31'),
('2020-07-30'),
('2020-07-29'),
('2020-07-28'),
('2020-07-27'),
('2020-07-26'),
('2020-07-25'),
('2020-07-24'),
('2020-07-23'),
('2020-07-22'),
('2020-07-21'),
('2020-07-20'),
('2020-07-19'),
('2020-07-18'),
('2020-07-17'),
('2020-07-16'),
('2020-07-15'),
('2020-07-14'),
('2020-07-13'),
('2020-07-12'),
('2020-07-11'),
('2020-07-10'),
('2020-07-09'),
('2020-07-08'),
('2020-07-07'),
('2020-07-06'),
('2020-07-05'),
('2020-07-04'),
('2020-07-03'),
('2020-07-02'),
('2020-07-01'),
('2020-06-30'),
('2020-06-29'),
('2020-06-28'),
('2020-06-27'),
('2020-06-26'),
('2020-06-25'),
('2020-06-24'),
('2020-06-23'),
('2020-06-22'),
('2020-06-21'),
('2020-06-20'),
('2020-06-19'),
('2020-06-18'),
('2020-06-17'),
('2020-06-16'),
('2020-06-15'),
('2020-06-14'),
('2020-06-13'),
('2020-06-12'),
('2020-06-11'),
('2020-06-10'),
('2020-06-09'),
('2020-06-08'),
('2020-06-07'),
('2020-06-06'),
('2020-06-05'),
('2020-06-04'),
('2020-06-03'),
('2020-06-02');

所需的输出:

date       | on_time_delivery_ratio

2020-07-31 | 0.75  
2020-07-30 | 0.69  
2020-07-29 | 0.68  
2020-07-28 | 0.80  
2020-07-27 | 0.79  
2020-07-26 | 0.78  
2020-07-25 | 0.69  
2020-07-24 | 0.72

我做了什么: 我已经能够创建一个指标,但只是针对当前日期。

SELECT curdate(),sum(case when promise_date=date(delivered_at) then 1 else 0 end)/count(*)*100 
 "On-Time Delivery Rate (%)"
from packages p 
where p.seller_id=123 and date(created_at) between DATE_SUB(curdate(),interval 30 day) and 
DATE_SUB(curdate(),interval 1 day); 

我需要帮助的地方:我需要日期表中的日期,而不是使用 curdate(),作为所需输出的第一列和这些日期的指标。

SQL 小提琴: http://sqlfiddle.com/#!9/b665ca1/2

【问题讨论】:

您可以将包表与日期表连接起来以从那里获取日期字段,而不是使用curdate() 感谢您对 Abhijeet 发表评论。我已经这样做了,但是如果你在我的代码中看到,在第 4 行,你会看到 "between DATE_SUB(curdate()" ,这里不是 curdate,我不能使用/引用日期列。我会如果你能写代码,谢谢。谢谢 你能为此创建一个 sql fiddle 吗? sqlfiddle.com/#!9/b665ca1/2 这里是 Abhijeet,希望对您有所帮助。 for every date in the past 60 days - 你在这里指的是哪个日期。 【参考方案1】:

小提琴:http://sqlfiddle.com/#!9/b665ca1/7(基于http://sqlfiddle.com/#!9/b665ca1/2)

SELECT 
   delivered_at,
   sum(case when promise_date=date(delivered_at) then 1 else 0 end)/count(*)  "On-Time Delivery Rate (%)"
from packages p 
where p.seller_id=123 
  and date(delivered_at) between DATE_SUB(curdate(),interval 30 day) and DATE_SUB(curdate(),interval 1 day)
group by delivered_at;

输出:

delivered_at    On-Time Delivery Rate (%)
2020-07-07T07:42:16Z    1
2020-07-09T08:30:56Z    0
2020-07-10T07:50:24Z    1
2020-07-22T06:33:22Z    1

编辑:选择过去 61 天

SELECT date.d,sum(case when promise_date=date(delivered_at) then 1 else 0 end)/count(*)*100 
 "On-Time Delivery Rate (%)"
from date 
CROSS JOIN packages p 
where p.seller_id=123 
  and date(created_at) between DATE_SUB(date.d,interval 30 day) and DATE_SUB(date.d,interval 1 day)
  and date.d >= DATE_SUB(curdate(),interval 61 day)
GROUP BY date.d
ORDER BY date.d; 
我将您查询中的 curdate() 更改为值 date.d。 select * from date 应提供所有日期,至少从过去 61 天开始。

【讨论】:

嗨 Luuk,感谢您的回答,但这并不是我真正想要的。在输出的第一列日期中,它应该来自日期表,因为我们需要今天和今天之前 60 天的 OTD。所以,我们总共有 61 行,这里的 Delivered_at 是不正确的。 嘿 Luuk,这行得通。珍惜你的时间。不过,我有一个快速的问题。我真的很想简单地理解“交叉加入”和“分组依据”在这里做了什么。你能解释一下吗? CROSS JOIN 子句没有连接谓词。换句话说,它没有 ON 或 USING 子句。 more info。 GROUP BY 是相当标准的 SQL,CROSS JOINGROUP BY 的组合就是结合了这些东西。 (还是我误解了你的问题?.?) 感谢 Luuk 的回复。我确实知道什么是交叉连接和分组依据,但我只是想简单解释一下在这种特定情况下这两者的组合如何得到我们想要的输出。 CROSS JOIN 的结果应被视为结果。在此结果上应用 GROUP BY【参考方案2】:

您想在dates table 中获取所有日期的 OTD 百分比,并获取相应日期的指标。 因此百分比计算为:((过去 30 天和日期前一天之间的准时交货次数)/(过去 30 天和日期前一天之间的总交货次数))*100;

因此,如果您以日期 2020-06-02 为例,则在 2020-05-02 至 2020-06-01 之间共有 3 次交付,其中 1 次按时交付,因此 OTD 百分比 = 33.3

据我了解,这是您可能正在寻找的解决方案:

请查看SQL fiddle:

SELECT d.fulldate,sum(case when promise_date = date(delivered_at) 
                      and p.seller_id = 123 and date(created_at) between DATE_SUB(d.fulldate,interval 30 day) and 
DATE_SUB(d.fulldate,interval 1 day) then 1 else 0 end)/sum(case when date(created_at) between DATE_SUB(d.fulldate,interval 30 day) and 
DATE_SUB(d.fulldate,interval 1 day) and p.seller_id = 123 then 1 else 0 end)*100
"On-Time Delivery Rate (%)"
from packages p, dates d group by d.fulldate;
where p.seller_id=123 and date(created_at) between DATE_SUB(d.fulldate,interval 30 day) and 
DATE_SUB(d.fulldate,interval 1 day);

输出:

以下是部分输出:(对于完整输出,您可以查看查询上方给出的 Fiddle)

fulldate    On-Time Delivery Rate (%)
2020-06-02  33.3333
2020-06-03  33.3333
2020-06-04  50
2020-06-05  50
2020-06-06  50
2020-06-07  50

【讨论】:

感谢您抽出时间来处理这个 Abhijeet;似乎解决方案有点复杂。能否请您解释一下如何在此处使用 group by 交叉加入?

以上是关于无法在 SQL 中将日期放在列中,将指标放在另一个列中的主要内容,如果未能解决你的问题,请参考以下文章

在 SQL 中将 AND 或 OR 放在一个条件中

是否可以在android中将一个视图放在另一个视图上?

无法在 MySQL 查询中将字符串转换为日期时间

如何在标准 SQL 中将 Epoch 时间戳转换为日期

Sql 从一个表列中选择一个最小值,并在一个 SQL 语句中将结果插入到另一个表列中

在 Excel 中将日期与字符串连接起来