1

我正在搜索网络和stackoverflow,但没有找到答案。:(所以请帮助我,我还在学习和阅读,但我还没有正确思考,没有 IF 和 FOR LOOP 可以做事。:)

我有表1:

  id|  date    |state_on_date|year_quantity
   1|30.12.2013|23           |100
   1|31.12.2013|25           |100 
   1|1.1.2014  |35           |150 
   1|2.1.2014  |12           |150 
   2|30.12.2013|34           |200 
   2|31.12.2013|65           |200 
   2|1.1.2014  |43           |300 

我试图得到:

表2:

id|  date    |state_on_date|year_quantity|state_on_date_compare
 1|30.12.2013|    23       |100          |23
 1|31.12.2013|    25       |100          |-2 
 1|1.1.2014  |    35       |150          |-10 
 1|2.1.2014  |    12       |150          |23 
 2|30.12.2013|    34       |200          |34
 2|31.12.2013|    65       |200          |-31 
 2|1.1.2014  |    43       |300          |22 

获取数字的规则:

id|date  |state_on_date|year_quantity|state_on_date_compare
 1|30.12.2013|   23    |100| 23 (lowest state_on_date for id 1)
 1|31.12.2013|   25    |100| -2 (23-25)
 1|  1.1.2014|   35    |150|-10 (25-35)
 1|  2.1.2014|   12    |150| 23 (35-12)
 2|30.12.2013|   34    |200| 34 (lowest state_on_date for id 2)
 2|31.12.2013|   65    |200|-31 (34-65)
 2|  1.1.2014|   43    |300| 22 (65-43)

感谢您提出的每一个建议或解决方案。

4

3 回答 3

1

Johnny Bones 在他的回答中提出了一些很好的观点,但实际上有一种方法可以让 Access SQL 在这种情况下执行所需的计算。我们的样本数据位于名为 [table1] 的表中:

id  date        state_on_date  year_quantity
--  ----------  -------------  -------------
 1  2013-12-20             23            100
 1  2013-12-31             25            100
 1  2014-01-01             25            150
 1  2014-01-02             12            150
 2  2013-12-30             34            200
 2  2013-12-31             65            200
 2  2014-01-01             43            300

第 1 步:确定每个 [id] 的初始行

我们首先在 Access 中创建一个名为 [StartDatesById] 的已保存查询,以便为我们提供每个 [id] 的最早日期

SELECT id, MIN([date]) AS MinOfDate
FROM table1
GROUP BY id

这给了我们

id  MinOfDate 
--  ----------
 1  2013-12-30
 2  2013-12-30

现在我们可以在另一个查询中使用它来为每个 [id] 提供初始行

SELECT 
    table1.id, 
    table1.date, 
    table1.state_on_date, 
    table1.year_quantity, 
    table1.state_on_date AS state_on_date_compare
FROM
    table1
    INNER JOIN
    StartDatesById
        ON table1.id = StartDatesById.id
            AND table1.date = StartDatesById.MinOfDate

这给了我们

id  date        state_on_date  year_quantity  state_on_date_compare
--  ----------  -------------  -------------  ---------------------
 1  2013-12-30             23            100                     23
 2  2013-12-30             34            200                     34

第 2 步:计算后续行

此步骤首先创建一个名为 [PreviousDates] 的已保存查询,该查询使用 [table1] 上的自连接为我们提供 [table1] 中不是该 [id] 第一行的每一行的先前日期

SELECT
    t1a.id,
    t1a.date,
    MAX(t1b.date) AS previous_date
FROM
    table1 AS t1a
    INNER JOIN
    table1 AS t1b
        ON t1a.id = t1b.id
            AND t1a.date > t1b.date
GROUP BY
    t1a.id,
    t1a.date

该查询给了我们

id  date        previous_date
--  ----------  -------------
 1  2013-12-31  2013-12-30   
 1  2014-01-01  2013-12-31   
 1  2014-01-02  2014-01-01   
 2  2013-12-31  2013-12-30   
 2  2014-01-01  2013-12-31   

再一次,我们可以在另一个查询中使用该查询来导出每个 [id] 的后续记录

SELECT
    curr.id,
    curr.date,
    curr.state_on_date,
    curr.year_quantity,
    prev.state_on_date - curr.state_on_date AS state_on_date_compare
FROM
    (
        table1 AS curr
        INNER JOIN
        PreviousDates
            ON curr.id = PreviousDates.id
                AND curr.date = PreviousDates.date
    )
    INNER JOIN
    table1 AS prev
        ON prev.id = PreviousDates.id
            AND prev.date = PreviousDates.previous_date

返回

id  date        state_on_date  year_quantity  state_on_date_compare
--  ----------  -------------  -------------  ---------------------
 1  2013-12-31             25            100                     -2
 1  2014-01-01             35            150                    -10
 1  2014-01-02             12            150                     23
 2  2013-12-31             65            200                    -31
 2  2014-01-01             43            300                     22

第 3 步:结合第 1 步和第 2 步的结果

要结合前两个步骤的结果,我们只需将它们都包含在 UNION 查询中并按前两列排序

    SELECT 
        table1.id, 
        table1.date, 
        table1.state_on_date, 
        table1.year_quantity, 
        table1.state_on_date AS state_on_date_compare
    FROM
        table1
        INNER JOIN
        StartDatesById
            ON table1.id = StartDatesById.id
                AND table1.date = StartDatesById.MinOfDate
UNION ALL
    SELECT
        curr.id,
        curr.date,
        curr.state_on_date,
        curr.year_quantity,
        prev.state_on_date - curr.state_on_date AS state_on_date_compare
    FROM
        (
            table1 AS curr
            INNER JOIN
            PreviousDates
                ON curr.id = PreviousDates.id
                    AND curr.date = PreviousDates.date
        )
        INNER JOIN
        table1 AS prev
            ON prev.id = PreviousDates.id
                AND prev.date = PreviousDates.previous_date
ORDER BY 1, 2

返回

id  date        state_on_date  year_quantity  state_on_date_compare
--  ----------  -------------  -------------  ---------------------
 1  2013-12-30             23            100                     23
 1  2013-12-31             25            100                     -2
 1  2014-01-01             35            150                    -10
 1  2014-01-02             12            150                     23
 2  2013-12-30             34            200                     34
 2  2013-12-31             65            200                    -31
 2  2014-01-01             43            300                     22
于 2014-01-09T23:13:42.613 回答
1

您必须了解 SQL 由于表示问题而具有误导性。就像在 The Matrix(“没有勺子”)中一样,在查询中没有以前的记录。

SQL 基于集合论,没有记录的顺序。所有记录都只是集合成员。SQL 背后的理论是,您通常所做的任何事情都应该被视为您正在同时对所有记录执行此操作!SELECT 查询的数据表视图在记录 B 之前显示记录 A 的事实是呈现的产物 - 而不是实际的记录顺序。

事实上,查询返回的记录与它们在表中出现的顺序相同,除非您包含了 GROUP BY 或 ORDER BY 子句。并且表中记录出现的顺序通常是它们的创建顺序,除非该表上有一个功能主键。

但是,这两种说法都会给您带来同样的问题。NEXT 和 PREVIOUS 的概念没有语法,因为它是 SQL 中不存在的顺序概念。

VBA 记录集虽然基于 SQL 作为记录源,但会创建一个额外的上下文来封装 SQL 上下文。这就是为什么 VBA 可以做你想做的事而 SQL 本身不能。这是“额外”的上下文,VBA 可以在其中定义保存您想要记住的内容的变量,直到出现另一条记录。

现在在你的游行中下雨了,这里有一些可能会有所帮助的想法。

  1. 当您想查看“以前的记录”数据时,Access 必须有一种方法可以找到您认为是“以前的记录”的内容。因此,如果您没有允许这种情况,那就是设计缺陷。(基于您没有意识到 SET 理论的含义,这对于新 Access 用户来说是完全可以原谅的,所以不要太难过。)这是基于“老程序员规则”,即“Access 不能告诉你”任何你没有先告诉它的事情。” 这意味着 - 实际上 - 如果订单对您意味着什么,您必须为 Access 提供记住所需的数据,然后再强制执行该订单。如果您没有变量来识别与数据集相关的正确顺序,则以后不能强加所需的顺序。在这种情况下,

  2. 您有时可以在查询中执行 DLookup 之类的操作,在该查询中根据某些订单标识符查找将在当前记录之前的记录。

例如,如果您按日期/时间字段排序,并且表示“以前”表示下一个时间早于焦点记录的记录,则您将选择最大日期小于焦点日期的记录。查看 DMax 函数。另请注意,我说的是“焦点记录”而不是“当前记录”。这是一个很好的观点,但“当前”也意味着按内涵排序。(“上一个”和“下一个”意味着按指称排序,这是一个更强的定义。)

无论如何,考虑一下这个小宝石:

DLookup( "[myvalue]", "mytable", "[mytable]![mydate] = #" & CStr( DMax( "[mydate]", "mytable", "[mytable]![mydate] < #" & CStr( [mydate] ) & "#)" ) & "#" )

我不保证括号对于函数是平衡的,也不保证语法完全正确。对 DLookup、DMax、Cstr 和字符串(在函数中)使用 Access 帮助以获得准确的语法。这个想法是使用查询(由 DMax 暗示)找到小于焦点日期的最大日期,以便提供查询(由 DLookup 暗示)以找到具有该日期的记录的值。CStr 将日期/时间变量转换为字符串,因此您可以使用“#”符号作为日期字符串括号。

如果您正在处理具有不同限定符的记录的不同日期,您还必须在 DMax 和 DLookup 函数中包含其余的限定符。这种语法变得非常讨厌非常快。这就是人们首先选择 VBA 的原因。

于 2014-01-09T22:16:39.220 回答
0

我希望这会有所帮助 http://blogs.lessthandot.com/index.php/DataMgmt/DataDesign/calculating-mean-median-and-mode-with-sq

您可以使用 select * from table1 into table2 指定您的条件,我不确定这是否可行

于 2014-01-09T21:24:41.730 回答