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

时间:2017-08-15 17:33:16

标签: sql excel-vba ms-access self-join isnull

我正在尝试在表格上写一个sql查询,它会给我类似于以下链接中的Formula_Based表格的结果[参见sample.xlsx中的Formula_Based表格]:

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,APPEARED DATE)是否在过去推出180或更多。所以我需要一个Previous Date列(> 180列),这将显示过去ATTR ='NEW'的最早日期> 180。

我已经完成了LEFT JOIN以获取表的所有行(32行但只获得25行)。我无法在无法确定以前日期的地方添加NULL。 [请参阅Sample.xlsx中的Query_Based表格。)

如何向y。[出现日期]列(即上一个日期列)添加空格或NULL?是否有更好,更有效的方法来编写此查询?

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

1 个答案:

答案 0 :(得分:1)

为了简洁起见,我将简单地将列[CTY],[CAT],[OWN],[BRD],[EXT]列作为"键"。

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

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

  1. 如果条件TEMP.[Attr] = "New"在同一查询中应用(例如在WHERE子句中),那将排除在左连接中返回Null行的可能性,因此最终结果将只包含非行的行-null"发布日期> 180天"。到目前为止,这是25行而不是全部32行的原因。
  2. Access要求每个联接操作都包含每个表中的列,因此不允许使用T1.[Attr] = "New"之类的内容。有一些技巧可以绕过这个限制,但是由于上一个原因,仍然需要一个单独的子查询,并且将条件添加到WHERE子句就好了,而不是进一步搞乱连接。
  3. 最后,这是完整的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);
    

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

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

    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;