【问题标题】:MS Access SQL query - Count records until value is metMS Access SQL 查询 - 计数记录直到满足值
【发布时间】:2021-06-06 19:19:40
【问题描述】:

我有一个 Access 查询 (qr1),它返回以下数据:

dateField stringField1 stringField2 booleanField
11/09/20 17:15 John Nick 0
12/09/20 17:00 John Mary -1
13/09/20 17:30 Ann John 0
13/09/20 19:30 Kate Alan 0
19/09/20 19:30 Ann Missy 0
20/09/20 17:15 Jim George 0
20/09/20 19:30 John Nick 0
27/09/20 15:00 John Mary -1
27/09/20 17:00 Ann John -1
27/09/20 19:30 Kate Alan 0
28/09/20 18:30 Ann Missy -1
03/10/20 18:30 Jim George -1
04/10/20 15:00 John Nick 0
04/10/20 17:15 John Mary 0
04/10/20 20:45 Ann John 0
05/10/20 18:30 Kate Alan 0
17/10/20 15:00 Jim George 0
17/10/20 17:15 John Nick 0
18/10/20 15:00 John Mary -1
18/10/20 17:15 Ann John 0

注意事项:

  • 字符串数据可以重复也可以不重复。
  • 日期数据存储为字符串。我使用一个函数将其转换为日期。
Public Function STR2TIME(sTime As String) As Date
Dim arr() As String
    sTime = Replace(sTime, ".", "/")
    arr = Split(sTime, "  ")
    STR2TIME = DateValue(Format(arr(0), "dd/mm/yyyy")) + TimeValue(arr(1))
End Function
  • qr1 按 STR2TIME(dateField) ASC 排序

现在我需要运行一个额外的查询来执行以下操作:

  • 添加一个额外的列,其中:
  • 计数记录直到是 (-1) 布尔字段
  • 此后,从 1 开始重新计数

在这种情况下,输出应如下所示:

dateField stringField1 stringField2 booleanField countField
11/09/20 17:15 John Nick 0 1
12/09/20 17:00 John Mary -1 2
13/09/20 17:30 Ann John 0 1
13/09/20 19:30 Kate Alan 0 2
19/09/20 19:30 Ann Missy 0 3
20/09/20 17:15 Jim George 0 4
20/09/20 19:30 John Nick 0 5
27/09/20 15:00 John Mary -1 6
27/09/20 17:00 Ann John -1 1
27/09/20 19:30 Kate Alan 0 1
28/09/20 18:30 Ann Missy -1 2
03/10/20 18:30 Jim George -1 1
04/10/20 15:00 John Nick 0 1
04/10/20 17:15 John Mary 0 2
04/10/20 20:45 Ann John 0 3
05/10/20 18:30 Kate Alan 0 4
17/10/20 15:00 Jim George 0 5
17/10/20 17:15 John Nick 0 6
18/10/20 15:00 John Mary -1 7
18/10/20 17:15 Ann John 0 1

问题

我尝试了很多方法,结果都是错误的。

最后我认为计算从当前日期到前一个日期的零(比当前最大和更小)可以解决问题:

SELECT t.*, (SELECT COUNT(*)
             FROM qr1 tt 
             WHERE booleanField = 0
             AND STR2TIME(tt.dateField) >= (SELECT TOP 1 dateField
                                           FROM qr1
                                           WHERE booleanField = -1
                                           AND STR2TIME(dateField) < STR2TIME(t.dateField)
                                           ORDER BY STR2TIME(dateField) DESC
                                          )
             AND STR2TIME(tt.dateField) <= STR2TIME(t.dateField)
            ) AS CountMatches
FROM qr1 t;

但在 countField 上仍然给我错误的数字结果:

countField
0
0
1
2
3
4
5
6
1
2
3
1
12
13
14
15
16
17
18
13

我做错了什么?我无法得到它。如何得到想要的结果?


编辑:

我将根据@Gordon Linoff 和@Gustav 的回答发布最终代码,稍微简化。

变化说明:

  • 我在这一步去掉了转换功能。我不是在每条记录中转换 7 次 *,而是在第一个查询中只转换一次,在这里可以比较值。
  • 我省略了检查零,因为没有必要。
  • 我添加了 NZ 函数以在内部子查询返回 NULL 时获取值。那是当没有任何“是”时,可以从较小的日期开始计算(通常是第一条记录)。
  • 剩下的唯一问题是,对于 NZ,我得到的值比我需要的少 1,所以我在 dateField 中添加了 -1 以增加 1。

代码如下:

SELECT t.*, (SELECT COUNT(*) FROM qr2 tt 
             WHERE tt.dateField <= t.dateField
             AND tt.dateField > NZ((SELECT TOP 1 dateField FROM qr2 
                                    WHERE booleanField = True
                                    AND dateField < t.dateField
                                    ORDER BY dateField DESC
                                    ), tt.dateField - 1) 
            ) AS CountMatches
FROM qr2 AS t;

【问题讨论】:

  • MS Access 是这种类型的数据操作的错误数据库。我的建议是你升级。

标签: sql ms-access


【解决方案1】:

这是可行的,虽然有点复杂:

Select 
    qr1.dateField, 
    qr1.stringField1, 
    qr1.stringField2, 
    qr1.booleanField, 

        (Select Count(*) From qr1 As t1 
        Where 
            (t1.booleanfield = true And t1.dateField = qr1.dateField) 
            Or
            (t1.booleanfield = false And t1.dateField <= qr1.dateField And 
            t1.dateField >= Nz(
                (Select Top 1 dateField From qr1 As t 
                Where t.dateField < qr1.dateField And t.booleanField = True 
                Order By t.dateField Desc), 
                t1.dateField ))) As countField

From 
    qr1;

输出:

你的字符串转换器可以用这个表达式代替:

TrueDate = CDate(Replace(TextDotDate, ".", "/"))

你应该在更早的时候申请,比如qr1

【讨论】:

  • 谢谢。你是对的,我会更早地应用转换。虽然我不会经常运行这个查询,但是在这个查询中多次使用转换函数完全是浪费。
【解决方案2】:

一个明显的问题是:

         AND STR2TIME(tt.dateField) >= (SELECT TOP 1 dateField

这应该是:

         AND STR2TIME(tt.dateField) >= (SELECT TOP 1 STR2TIME(dateFielda)

第二,你有:

WHERE booleanField = 0

但我认为这个过滤器不合适。

【讨论】:

  • 谢谢。这确实很明显。我接受@Gustav 的回答,因为它更完整。例如它还包括 booleanField 第一次为 True 的情况,因此“先前”值为 Null。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多