1

问题是这些客户在任何给定日期都是混蛋多久。

我正在对抗 Sybase

对于这个表history_data的简化表结构

表:history_of_jerkiness
处理日期名称 is_jerk
--------------- ----- --------
20090101 亚光真
20090101 鲍勃假        
20090101 亚历克斯真        
20090101 卡罗尔真        
20090102 亚光真        
20090102 鲍勃真        
20090102 亚历克斯假        
20090102 卡罗尔真        
20090103 亚光真        
20090103 鲍勃真        
20090103 亚历克斯真        
20090103 卡罗尔假        

第 3 次的报告应该显示,马特一直是个混蛋,亚历克斯刚刚成为一个混蛋,鲍勃已经混蛋了 2 天。

名字天生涩
----- ----------
马特 3
鲍勃 2
亚历克斯 1

我想动态地找到这些时间跨度,所以如果我第二次运行报告,我应该得到不同的结果:

名称 days_jerky
----- ----------
马特 2
鲍勃 1
颂歌 2

这里的关键是试图只找到比某个日期更早的连续跨度。我找到了一些线索,但这似乎是一个有非常聪明的棘手解决方案的问题。

4

4 回答 4

2

我的 SQL Server 解决方案 - 与 Dems 相同,但我自己设置了一个最小基线。它假设没有间隙——也就是说,每个人每天都有一个条目。如果那不是真的,那么我将不得不循环。

DECLARE @run_date datetime
DECLARE @min_date datetime

SET @run_date = {d '2009-01-03'}

-- get day before any entries in the table to use as a false baseline date
SELECT @min_date = DATEADD(day, -1, MIN(processing_date)) FROM history_of_jerkiness

-- get last not a jerk date for each name that is before or on the run date
-- the difference in days between the run date and the last not a jerk date is the number of days as a jerk
SELECT [name], DATEDIFF(day, MAX(processing_date), @run_date)
FROM (
     SELECT processing_date, [name], is_jerk
     FROM history_of_jerkiness
     UNION ALL
     SELECT DISTINCT @min_date, [name], 0
     FROM history_of_jerkiness ) as data
WHERE is_jerk = 0
  AND processing_date <= @run_date
GROUP BY [name]
HAVING DATEDIFF(day, MAX(processing_date), @run_date) > 0

我使用以下内容创建了测试表:

CREATE TABLE history_of_jerkiness (processing_date datetime, [name] varchar(20), is_jerk bit)

INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-01'}, 'Matt', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-01'}, 'Bob', 0)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-01'}, 'Alex', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-01'}, 'Carol', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-02'}, 'Matt', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-02'}, 'Bob', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-02'}, 'Alex', 0)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-02'}, 'Carol', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-03'}, 'Matt', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-03'}, 'Bob', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-03'}, 'Alex', 1)
INSERT INTO history_of_jerkiness (processing_date, [name], is_jerk) VALUES ({d '2009-01-03'}, 'Carol', 0) 
于 2009-03-11T16:56:56.100 回答
1

如果您构建数据以满足以下标准,这可以变得简单......

所有的人都必须有一个他们不是混蛋的初始记录

你可以做类似...

SELECT
   name,
   MAX(date)   last_day_jerk_free
FROM
   jerkiness AS [data]
WHERE
   jerk = 'false'
   AND date <= 'a date'
GROUP BY
   name

您已经知道基准日期是什么(“日期”),现在您知道他们不是混蛋的最后一天。我不知道 sybase,但我确信您可以使用一些命令来获取“a data”和“last_day_jerk_free”之间的天数

编辑:

有多种方法可以人为地创建初始化的“非生涩”记录。Will Rickards 建议使用包含联合的子查询。但是,这样做有两个缺点……
1. 子查询屏蔽了任何可能已使用的索引
2. 它假设所有人都有从同一点开始的数据

或者,采用 Will Rickard 的建议并将聚合从外部查询移动到内部查询(从而最大限度地利用索引),并与通用的第二个子查询联合以创建起始 jerky = false 记录......

SELECT name, DATEDIFF(day, MAX(processing_date), @run_date) AS days_jerky
FROM (

    SELECT name, MAX(processing_date) as processing_date
    FROM history_of_jerkiness
    WHERE is_jerk = 0 AND processing_date <= @run_date
    GROUP BY name

    UNION

    SELECT name, DATEADD(DAY, -1, MIN(processing_date))
    FROM history_of_jerkiness
    WHERE processing_date <= @run_date
    GROUP BY name

    ) as data
GROUP BY
   name

外部查询仍然必须在没有索引的情况下执行最大值,但记录数量会减少(每个名称 2 个,而不是每个名称 n 个)。由于不要求每个名称对每个使用日期都有一个值,因此也减少了记录的数量。还有很多其他方法可以做到这一点,其中一些可以在我的编辑历史中看到。

于 2009-03-11T16:32:45.720 回答
1

“如果您构建数据以满足以下标准,这可以变得简单......

所有人都必须有一个他们不是混蛋的初始记录”

数据应该和不应该满足的标准取决于用户,而不是开发人员。

于 2009-06-18T16:50:51.577 回答
0

这个怎么样:

select a.name,count(*) from history_of_jerkiness a
left join history_of_jerkiness b
on a.name = b.name 
and a.processing_date >= b.processing_date
and a.is_jerk = 'true'
where not exists
( select * from history_of_jerkiness c
  where a.name = c.name
  and c.processing_date between a.processing_date and b.processing_date
  and c.is_jerk = 'false'
)
and a.processing_date <= :a_certain_date;
于 2009-03-11T17:48:53.293 回答