MSAccess SQL 查询以查找过去 >180 的最新日期

MSAccess SQL query to find latest date >180 in past

我正在尝试在 table 上编写一个 sql 查询,这将给我类似于下面 link 中的 Formula_Based sheet 的结果] [参见 sample.xlsx 中的 Formula_Based sheet:

Sample.xlsx

我设法编写的查询是:

SELECT x.[CTY], x.[CAT], x.[OWN], x.[BRD], x.[EXT], x.[appeared date], y.[appeared date], x.[ATTR], y.[ATTR]
    FROM TEMP AS x 
    LEFT JOIN 
    (
    SELECT  [CTY], [CAT], [OWN], [BRD], [EXT], [appeared date], MIN([appeared date]),[ATTR]
    FROM TEMP 
    GROUP BY [CTY], [CAT], [OWN], [BRD], [EXT], [appeared date],[ATTR]
    ) AS y 
    ON 
    (
    x.[CAT]=y.[CAT]
    AND x.[CTY]=y.[CTY]
    AND x.[OWN]=y.[OWN]
    AND x.[BRD]=y.[BRD]
    AND x.[EXT]=y.[EXT]
    AND x.[appeared date] > y.[appeared date]
    AND x.[appeared date] - y.[appeared date]>180 
    )
    GROUP BY x.[CTY], x.[CAT], x.[OWN], x.[BRD], x.[EXT], x.[appeared date],y.[appeared date],x.[ATTR],y.[ATTR]
    HAVING y.[ATTR]="NEW" 

数据有更多列,但我只显示了最需要的列。数据按以下列顺序排序,即。 CTY、CAT、OWN、BRD、EXT、出现日期。我想知道的是同一产品(具有相同的 CTY、CAT、OWN、BRD、EXT、出现日期)是否在过去 180 次或更长时间内推出。所以我需要一个 Previous Date 列(>180 列),它会显示过去 ATTR = 'NEW' 的最早日期 >180。

我进行了 LEFT JOIN 以获取 table 的所有行(32 行但仅获取 25 行)。我无法在无法确定以前日期的地方添加 NULL。 [参见 Sample.xlsx 中的 Query_Based sheet。

如何向 y.[appeared date] 列(即上一个日期列)添加空格或 NULL?有没有更好更有效的方法来编写这个查询?

P.S: 我运行 MSAccess 中的查询。

为了简洁起见,我将 [CTY]、[CAT]、[OWN]、[BRD]、[EXT] 列组简称为 "key"。

原始查询和另一个答案犯了一个基本的选择错误:内部查询选择每个键只选择一个日期,即MIN([appeared date]),但最多最近的 "launch" 日期(> 180 天)因同一键的 [appeared date] 的不同值而异。因此,子查询必须在选择最近的启动日期之前应用日期条件。换句话说,必须在 Max([appeared date]) 表达式和相应的分组之前应用条件“> 180 天”。 (仅供参考:因为连接条件是在聚合操作之前应用的,所以在同一个查询中同时具有两个条件并且仍然满足正确的应用顺序就足够了。)

发布日期也符合条件[Attr] = "New"。这必须在其自己的子查询中应用,原因至少有两个:

  1. 如果在同一查询中应用条件 TEMP.[Attr] = "New"(例如在 WHERE 子句中),这将排除在左连接中返回 Null 行的可能性,因此最终结果将仅包括行非空 "launch dates >180 days"。这就是到目前为止尝试的 25 行而不是全部 32 行的原因。
  2. Access 要求每个连接操作都包含来自每个 table 的列,因此不允许像 T1.[Attr] = "New" 这样的操作。有一些技巧可以绕过这个限制,但是由于前面的原因仍然需要一个单独的子查询,并且将条件添加到 WHERE 子句而不是进一步混淆连接同样简单。

最后,这是完整的 SQL 查询:

    SELECT TEMP.CTY, TEMP.CAT, TEMP.OWN, TEMP.BRD, TEMP.EXT,
        TEMP.[Appeared date], TEMP.ATTR, GT180.[GT180 date],
        (TEMP.[Appeared date]-[GT180 date]) AS diff_h
    FROM TEMP 
        LEFT JOIN 
        (SELECT T2.CTY, T2.CAT, T2.OWN, T2.BRD, T2.EXT,
             T2.[Appeared date], Max(News.[Appeared date]) AS [GT180 Date]
         FROM TEMP AS T2
             LEFT JOIN
                 (SELECT T1.CTY, T1.CAT, T1.OWN, T1.BRD, T1.EXT, T1.[Appeared date], T1.ATTR 
                  FROM TEMP AS T1
                  WHERE (T1.ATTR="New")) AS News
             ON (News.[Appeared date]<=T2.[Appeared date]-180) 
                 AND (T2.CTY = News.CTY) AND (T2.CAT = News.CAT)
                 AND (T2.OWN = News.OWN) AND (T2.BRD = News.BRD) AND (T2.EXT = News.EXT)
             GROUP BY T2.CTY, T2.CAT, T2.OWN, T2.BRD, T2.EXT, T2.[Appeared date])  AS GT180
        ON (TEMP.[Appeared date] = GT180.[Appeared date]) 
            AND (TEMP.EXT = GT180.EXT) AND (TEMP.BRD = GT180.BRD) AND (TEMP.OWN = GT180.OWN) 
            AND (TEMP.CAT = GT180.CAT) AND (TEMP.CTY = GT180.CTY);

注意:table [Temp] 在每个子查询中的别名不同,以避免 Access 在不同子查询中解释对相同 table 的引用时出现任何可能的问题。

这是使用参数化子查询的替代但等效的查询:

SELECT TEMP.CTY, TEMP.CAT, TEMP.OWN, TEMP.BRD, TEMP.EXT, 
    TEMP.[Appeared date], TEMP.ATTR, 
    (SELECT Max([Appeared Date]) AS [GT180 Date] 
     FROM TEMP AS T1
     WHERE ((T1.CTY=[TEMP].[CTY]) AND (T1.CAT=[TEMP].[CAT]) AND (T1.OWN=[TEMP].[OWN]) 
        AND (T1.BRD=[TEMP].[BRD]) AND (T1.EXT=[TEMP].[EXT]) 
        AND (T1.[Appeared date] < [TEMP].[Appeared Date]-180) AND (T1.ATTR="New"))
    ) AS [GT180 Date],
    [Appeared date]-[GT180 Date] AS diff_h
FROM TEMP;