sql 语句:一个字段,连续几天值大于0,获得天数 怎么解决的?请教
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sql 语句:一个字段,连续几天值大于0,获得天数 怎么解决的?请教相关的知识,希望对你有一定的参考价值。
a b
xxx 2011-6-1
ooo 2011-6-2
xxx 2011-6-3
xxx 2011-6-4
xxx 2011-6-5
判断是否存在连续三天a的值为xxx ,sql怎么写 最好是mysql的
可以将表下移一行后作差比较:
b 错行 差
1 2011-6-1
2 2011-6-3 2011-6-1 2
3 2011-6-4 2011-6-3 1
4 2011-6-5 2011-6-4 1
2011-6-5
然后再用游标判断差这一列是否有两个1是挨着的
或者直接判断时期是否连续,sqlserver里可以这样写
DECLARE @id INT
DECLARE @time DATETIME
DECLARE @tb TABLE (id INT IDENTITY(1,1) ,b DATETIME)
INSERT INTO @tb(b) SELECT b FROM tb ORDER BY b
SELECT @id=MIN(INT_I) FROM @tb
WHILE NOT @id IS NULL BEGIN
SELECT @time = b FROM @tb WHERE INT_I=@id
IF EXISTS(SELECT 1 FROM tb WHERE b = DATEADD(dd,1,@time))
BEGIN
IF EXISTS(SELECT 1 FROM tb WHERE b = DATEADD(dd,2,@time))
BEGIN
PRINT '存在!'
END
END
SELECT @id=MIN(id) FROM @tb WHERE id>@id
END 参考技术A 一个sql比较难.如果不是必须就是游标吧. 参考技术B
加一个用来判断的字段 ttt
该字段为0和1
如果纪录的上面一条记录的 ttt 为0 并且该纪录的bbb不是负 ttt 为 0
否则为1
然后根据 ttt,把1的去掉就行。
加入一系列日期并计算连续天数
【中文标题】加入一系列日期并计算连续天数【英文标题】:Joining series of dates and counting continous days 【发布时间】:2015-08-18 14:18:29 【问题描述】:假设我有一张如下表
date add_days
2015-01-01 5
2015-01-04 2
2015-01-11 7
2015-01-20 10
2015-01-30 1
我想要做的是检查days_balance
,即如果date
大于或小于前一个日期+ N天(add_days
),如果它们是连续系列,则取累计天数总和.
所以算法应该像这样工作
for i in 2:N_rows
days_balance[i] := date[i-1] + add_days[i-1] - date[i]
if days_balance[i] >= 0 then
date[i] := date[i] + days_balance[i]
预期的结果应该如下
date days_balance
2015-01-01 0
2015-01-04 2
2015-01-11 -3
2015-01-20 -2
2015-01-30 0
纯SQL可以吗?我想它应该带有一些条件连接,但看不到它是如何实现的。
【问题讨论】:
如果您使用的是 PostgreSQL 9.1.13 或更高版本,则需要查看 PostgresSQL 中的lag
和 lead
窗口函数。另外,您如何计算第一条记录的 previous_date 和 previous_add_days?
@FutbolFan 按当前和以前的日期我是指后续行 - 为了清楚起见,我将进行编辑。
是的,我知道了。但是,对于 date = 2015-01-01
的行,我要问的是该记录的 previous_date 和 previous_add_days 是多少?
预期结果是否正确?第四行不应该是-5吗?这是我的数学:第 01 天到第 4 天 = 0 余额减去 3 天变化 + 5 add_days = 2;第 04 天到第 11 天 = 2 余额减去 7 天变化 + 2 add_days = -3;第 11 天到第 20 天 = -3 余额减去 9 天变化 + 7 add_days = -5;第 20 天到第 30 天 = -5 余额减去 10 天变化 + 10 add_days = -5;
@FutbolFan 我更新了我的问题和伪代码 - 现在清楚了吗?
【参考方案1】:
我发布了另一个答案,因为比较它们可能会很好,因为它们使用不同的方法(这个只是进行 n^2 样式连接,另一个使用递归 CTE)。这一个利用了这样一个事实,即您不必在为特定行计算之前为每一行计算 days_balance ,您只需要将前几天的内容相加......
drop table junk
create table junk(date DATETIME, add_days int)
insert into junk values
('2015-01-01',5 ),
('2015-01-04',2 ),
('2015-01-11',7 ),
('2015-01-20',10 ),
('2015-01-30',1 )
;WITH cte as
(
select ROW_NUMBER() OVER (ORDER BY date) i, date, add_days, ISNULL(DATEDIFF(DAY, LAG(date) OVER (ORDER BY date), date), 0) days_since_prev
FROM Junk
)
, combinedWithAllPreviousDaysCte as
(
select i [curr_i], date [curr_date], add_days [curr_add_days], days_since_prev [curr_days_since_prev], 0 [prev_add_days], 0 [prev_days_since_prev] from cte where i = 1 --get first row explicitly since it has no preceding rows
UNION ALL
select curr.i [curr_i], curr.date [curr_date], curr.add_days [curr_add_days], curr.days_since_prev [curr_days_since_prev], prev.add_days [prev_add_days], prev.days_since_prev [prev_days_since_prev]
from cte curr
join cte prev on curr.i > prev.i --join to all previous days
)
select curr_i, curr_date, SUM(prev_add_days) - curr_days_since_prev - SUM(prev_days_since_prev) [days_balance]
from combinedWithAllPreviousDaysCte
group by curr_i, curr_date, curr_days_since_prev
order by curr_i
输出:
+--------+-------------------------+--------------+
| curr_i | curr_date | days_balance |
+--------+-------------------------+--------------+
| 1 | 2015-01-01 00:00:00.000 | 0 |
| 2 | 2015-01-04 00:00:00.000 | 2 |
| 3 | 2015-01-11 00:00:00.000 | -3 |
| 4 | 2015-01-20 00:00:00.000 | -5 |
| 5 | 2015-01-30 00:00:00.000 | -5 |
+--------+-------------------------+--------------+
【讨论】:
【参考方案2】:好吧,我想我有一个递归 CTE(抱歉,我目前只有 Microsoft SQL Server 可用,所以它可能不符合 PostgreSQL)。
我也认为你的预期结果是错误的(见上面的评论)。如果没有,这可能会被修改以符合您的数学。
drop table junk
create table junk(date DATETIME, add_days int)
insert into junk values
('2015-01-01',5 ),
('2015-01-04',2 ),
('2015-01-11',7 ),
('2015-01-20',10 ),
('2015-01-30',1 )
;WITH cte as
(
select ROW_NUMBER() OVER (ORDER BY date) i, date, add_days, ISNULL(DATEDIFF(DAY, LAG(date) OVER (ORDER BY date), date), 0) days_since_prev
FROM Junk
)
,recursiveCte (i, date, add_days, days_since_prev, days_balance, math) as
(
select top 1
i,
date,
add_days,
days_since_prev,
0 [days_balance],
CAST('no math for initial one, just has zero balance' as varchar(max)) [math]
from cte where i = 1
UNION ALL --recursive step now
select
curr.i,
curr.date,
curr.add_days,
curr.days_since_prev,
prev.days_balance - curr.days_since_prev + prev.add_days [days_balance],
CAST(prev.days_balance as varchar(max)) + ' - ' + CAST(curr.days_since_prev as varchar(max)) + ' + ' + CAST(prev.add_days as varchar(max)) [math]
from cte curr
JOIN recursiveCte prev ON curr.i = prev.i + 1
)
select i, DATEPART(day,date) [day], add_days, days_since_prev, days_balance, math
from recursiveCTE
order by date
结果是这样的:
+---+-----+----------+-----------------+--------------+------------------------------------------------+
| i | day | add_days | days_since_prev | days_balance | math |
+---+-----+----------+-----------------+--------------+------------------------------------------------+
| 1 | 1 | 5 | 0 | 0 | no math for initial one, just has zero balance |
| 2 | 4 | 2 | 3 | 2 | 0 - 3 + 5 |
| 3 | 11 | 7 | 7 | -3 | 2 - 7 + 2 |
| 4 | 20 | 10 | 9 | -5 | -3 - 9 + 7 |
| 5 | 30 | 1 | 10 | -5 | -5 - 10 + 10 |
+---+-----+----------+-----------------+--------------+------------------------------------------------+
【讨论】:
另外,我觉得这不是一个很好的解决方案,因为递归级别随着每一行而增加,所以只使用一些东西来迭代处理结果可能会更好/更有效(但是最初的问题不是要求那个)。【参考方案3】:我不太明白您的算法如何返回您的预期结果?但让我分享一个我想出的可能会有所帮助的技术。
这仅在您的数据的最终结果要导出到 Excel 时才有效,即使这样,它也不会在所有情况下都有效,具体取决于您导出数据集的格式,但在这里......
如果您熟悉 Excel 公式,我发现如果您在 SQL 中将 Excel 公式作为另一个字段编写,它会在您导出到 Excel 后立即为您执行该公式(适用于我只是将其复制并粘贴到 Excel 中,因此它不会将其格式化为文本)
因此,对于您的示例,您可以执行以下操作(再次注意我不理解您的算法,所以这可能是错误的,但这只是为了给您一个概念)
SELECT
date
, add_days
, '=INDEX($1:$65536,ROW()-1,COLUMN()-2)'
||'+INDEX($1:$65536,ROW()-1,COLUMN()-1)'
||'-INDEX($1:$65536,ROW(),COLUMN()-2)'
AS "days_balance[i]"
,'=IF(INDEX($1:$65536,ROW(),COLUMN()-1)>=0'
||',INDEX($1:$65536,ROW(),COLUMN()-3)'
||'+INDEX($1:$65536,ROW(),COLUMN()-1))'
AS "date[i]"
FROM
myTable
ORDER BY /*Ensure to order by whatever you need for your formula to work*/
完成这项工作的关键部分是使用INDEX
公式函数根据当前单元格的位置选择一个单元格。所以ROW()-1
告诉它获取上一条记录的结果,COLUMN()-2
表示从当前记录左侧的两列中获取值。因为您不能使用像A2+B2-A3
这样的单元格引用,因为行号在导出时不会改变,并且它假定列的位置。
我将 SQL 字符串连接与 ||
一起使用,以便在屏幕上更容易阅读。
我在excel中试过这个;它与您的预期结果不符。但是,如果这种技术对您有用,那么只需更正 excel 公式以适应。
【讨论】:
以上是关于sql 语句:一个字段,连续几天值大于0,获得天数 怎么解决的?请教的主要内容,如果未能解决你的问题,请参考以下文章