去年开始住所附近多了两只无主野猫,其中一只还跑我家楼上下不来,饿了几天,后来被两个“爱猫人士”拎着诱捕笼救了下来,今年这两只猫又繁殖了三只,平日这几只猫就游荡在附近的花坛里、屋檐下,慢慢地,发现这群猫带来的以下几个问题:

  1. 乱叫,发情期间哇哇乱叫,影响人休息,苦不堪言;
  2. 环境问题,这几只猫会翻垃圾箱,常常把那些没有盖盖子的垃圾桶翻的一地垃圾,爱心人士提供的猫吃不完的猫粮洒一地需要清理;
  3. 危害野生动物,之前花园里经常有斑鸠踱来踱去觅食,自从这几只猫在这里生活,几乎就见不到斑鸠下到地面觅食了,原因一方面是猫挤占了斑鸠的地面生存空间,另一方面,猫会威胁到地面觅食斑鸠的生命安全;
  4. 破坏电瓶车,这些猫会趴在电瓶车座位上休息,顺便会磨磨爪子,最近发现我的电瓶车座被猫抓了一二十个洞。

有时,新闻上那些对待猫狗作出过激行为的人,你不能盲目评判他是对是错,最好从源头上找原因,拿我这附近的这群无主野猫来说,问题的根源就在弃养他们的主人身上,不想养了就好好处理掉,不要不负责任地丢弃,成为别人的麻烦。

其实我不知道如何描述长期饮茶的危害,养生专家或者茶文化从业者可能会告诉你茶的各种好处,以我最近两年饮茶的切身体验总结,长期喝茶可能有一百种好处,至少有以下几点问题值得谨慎对待:

  • 嘴巴干涩,是那种越喝越干涩,越干涩越想喝的感觉,明明一直在喝茶,嘴巴为什么还是那么干涩;
  • 费钱,茶叶价格差异非常大,旱的旱死涝的涝死,总之,随着饮茶习惯的养成,以及对茶叶的深入了解,对茶叶的选择只会越来越挑,价格越来越高;另一方面,茶与生俱来的文化元素,总能让你愿意在一些形式上的东西上花钱,茶具至少得搞一些吧;
  • 危害牙齿美观,以前我有一口洁白的牙齿,随着饮茶习惯的养成,不管怎么刷,牙齿上的茶垢总是除之不尽;
  • 心态上的变化,喝茶和心态变老,这两者之间的到底谁是谁的因,谁是谁的果我不知道,反正我隐约感觉到心态上的些许微妙变化了。

离职同事跑到广东找工作,广东那边的面试官直接致电咨询我供职公司的熟人,询问此人的“工作能力”,这位熟人又把原委告诉了我。

这种通过熟人对前离职同事的调查,本人至少经历过三次了,世界真是太小了,特别是在大一点的公司,不管去哪里工作,你在上一家公司的工作态度、能力和人际关系,很容易影响到你的下一份工作,比预想的容易的多。

最近需要统计一项数据,原数据包含记录行生成的时间戳字段 OP_TIME 和一个自增序列中间可能不连续的单据编号 SWF_NUM,要求统计相邻两条记录的时间戳间隔不超过 10 分钟的最大连续记录数。概括起来有两个要求:

  1. 相邻两条记录的时间戳间隔不超过 10 分钟;
  2. 满足第 1 条的记录且连续不间断的最大记录数。

实现方法

整体思路是:

  1. 筛选出结果集;
  2. 处理结果集:
    • 对结果集中符合条件和不符合条件的记录打上标签;
    • 同时,通过 ROW_NUMBER() 对结果集排序编号。
  3. 第二次处理结果集:
    • 对处理好的结果集通过 ROW_NUMBER()=ROW_NUMBER()-1 自关联,过滤掉符合条件的记录;
    • 使用 ROW_NUMBER() 对查询结果第二次排序编号。
  4. 第三次处理结果集:
    • 利用排序编号 ROW_NUMBER()=ROW_NUMBER()-1 对第二次处理得到的结果集自关联;
    • 在查询结果中将第一次的排序编号相减,差值-1 就是连续记录数;
    • 对上述结果分组取最大值,得到最大连续记录数。

现在用 ROW_NUMBER() 对筛选好的源数据排序,自关联比较相邻记录的时间差,对符合要求的记录通过 ROW_NUMBER() 再排序,得到的结果通过第二次的 ROW_NUMBER() 值自关联,在查询结果中用第一次的 ROW_NUMBER() 值求差,差值就是符合条件的联续记录数,分组后取最大值,得到结果:

  1. 处理原数据,给结果加上按 OP_TIME 降序的 ROW_NUMBER(),取别名 SWF_ROW;
  2. 对上一步的结果,通过 SWF_ROW = SWF_ROW-1 自关联,比较相邻记录的时间差:在查询结果里对自关联的源数据记录比较时间戳,小于等于 10 分钟的赋值 1(下一步会丢弃这些记录),大于 10 分钟的赋值 0,取别名 TT;
  3. 对上一步的结果进行执行查询处理,条件里筛选出 TT=0 的记录,给执行结果加上按 SWF_ROW 降序的 ROW_NUMBER(),取别名 RNN,待下一步用;
  4. 最后,对第三步的结果通过 RNN=RNN-1 自关联,查询结果对 SWF_ROW-SWF_ROW 进行分组统计取最大值。

完整 sql 如下:

创建示例数据表:

CREATE TABLE ta (unit_id int, swf_num int, fscl_date date, op_time date DEFAULT CURRENT_TIMESTAMP);

写入测试数据:

INSERT INTO ta VALUES (1950, 1000, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:25:45', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1001, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:27:11', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1002, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:38:29', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1003, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:39:22', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1004, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:43:45', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1006, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:58:50', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1007, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 22:59:55', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1000, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 09:06:41', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1001, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 09:09:36', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1002, to_date('2020-06-27', 'YYYY-MM-DD'), to_date('2020-06-27 12:20:59', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1003, to_date('2020-06-28', 'YYYY-MM-DD'), to_date('2020-06-28 07:50:09', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1004, to_date('2020-06-28', 'YYYY-MM-DD'), to_date('2020-06-28 08:14:37', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1005, to_date('2020-06-28', 'YYYY-MM-DD'), to_date('2020-06-28 08:19:00', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1006, to_date('2020-06-28', 'YYYY-MM-DD'), to_date('2020-06-28 10:18:12', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1007, to_date('2020-06-28', 'YYYY-MM-DD'), to_date('2020-06-28 10:24:57', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1950, 1008, to_date('2020-06-29', 'YYYY-MM-DD'), to_date('2020-06-29 07:36:07', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1006, to_date('2020-06-29', 'YYYY-MM-DD'), to_date('2020-06-29 09:10:39', 'YYYY-MM-DD hh24:mi:ss'));
INSERT INTO ta VALUES (1957, 1007, to_date('2020-06-29', 'YYYY-MM-DD'), to_date('2020-06-29 12:30:19', 'YYYY-MM-DD hh24:mi:ss'));
WITH TEMP_TA AS ( --原始数据
	SELECT TA.UNIT_ID, TA.SWF_NUM, TA.OP_TIME, TA.FSCL_DATE
	  FROM TA
),
MA AS ( --最大时间记录
	SELECT X.UNIT_ID,MAX(X.SWF_NUM) AS MAX_SWF_NUM, X.FSCL_DATE, MAX(X.OP_TIME) AS OP_TIME
	  FROM TEMP_TA X
	 GROUP BY X.UNIT_ID,X.FSCL_DATE
),
MI AS ( --最小时间记录
	SELECT X.UNIT_ID,MIN(X.SWF_NUM) AS MIN_SWF_NUM,X.FSCL_DATE,MIN(X.OP_TIME) AS OP_TIME
	  FROM TEMP_TA X
  GROUP BY X.UNIT_ID,X.FSCL_DATE
),
XR AS (--处理源数据
  SELECT UN.*,ROW_NUMBER() OVER( PARTITION BY UN.UNIT_ID ORDER BY UN.UNIT_ID,UN.OP_TIME DESC) SWF_ROW
    FROM (
    --制造更小记录 开始 在第一个记录前制造一个记录号-1 的更小记录,防止开头出现符合条件的连续记录
    SELECT MI.UNIT_ID,MI.MIN_SWF_NUM-1 AS SWF_NUM, FSCL_DATE,
		   MI.OP_TIME-11/(24*60) AS OP_TIME --制单时间比第一个真实记录的制单时间早 11 分钟
    FROM MI MI --制造第一个相差分钟数大于 11 分钟(反正间隔大于 10 分钟就行)的记录,使之不符合要求
    --制造更小记录 结束
    UNION ALL
    --正常记录 开始
    SELECT X.UNIT_ID,X.SWF_NUM,X.FSCL_DATE,X.OP_TIME FROM TEMP_TA X
    --正常记录 结束
    UNION ALL
    --制造更大记录 开始 在第后一个记录后制造一个记录号+1 的更大记录 
    SELECT MA.UNIT_ID,MA.MAX_SWF_NUM + 1 AS SWF_NUM,FSCL_DATE,
		   MA.OP_TIME+11/(24*60) AS OP_TIME --制单时间比实际最后一个记录制单时间晚 6 分钟
    FROM MA MA  --制造第一个相差分钟数大于 11 分钟的记录,防止结尾出现符合条件的连续记录
    --制造更大记录 结束
  ) UN
),
FI AS(
  SELECT A.*, ROW_NUMBER() OVER(PARTITION BY A.UNIT_ID  ORDER BY A.UNIT_ID, A.SWF_ROW DESC) RNN
	FROM (
    SELECT XR.UNIT_ID,XR.SWF_ROW, XR.FSCL_DATE,
      CASE 
        WHEN ROUND((XR.OP_TIME - X.OP_TIME) * 24 * 60, 2) <= 10 THEN 1
        WHEN ROUND((XR.OP_TIME - X.OP_TIME) * 24 * 60, 2) >  10 THEN 0 
      END AS TT --是否符合间隔 10 分钟的条件,符合置 1 不符合置 0
    FROM XR XR
    LEFT JOIN XR X ON XR.UNIT_ID = X.UNIT_ID AND XR.FSCL_DATE = X.FSCL_DATE AND X.SWF_ROW - 1 = XR.SWF_ROW
    WHERE X.SWF_NUM IS NOT NULL
    ORDER BY XR.SWF_NUM DESC
  ) A
  WHERE A.TT = '0'
)
SELECT FI.UNIT_ID, FI.FSCL_DATE, MAX(FI.SWF_ROW - NVL(FI2.SWF_ROW,0)) MAX_CNT
  FROM FI
LEFT JOIN FI FI2 ON FI.UNIT_ID = FI2.UNIT_ID AND FI.RNN = FI2.RNN - 1
GROUP BY FI.UNIT_ID, FI.FSCL_DATE
HAVING MAX(FI.SWF_ROW-COALESCE(FI2.SWF_ROW,0)) > 1
ORDER BY FI.UNIT_ID,FI.FSCL_DATE

无名藕塘,没人欣赏。
初秋·藕塘·荷叶

初秋·藕塘·荷叶

初秋·藕塘

初秋·藕塘·蜻蜓