2017-08-15 147 views
1

我想写一个sql查询的表,这将给我的结果类似于下面的链接中的Formula_Based表[请参阅sample.xlsx中的Formula_Based表:]:MSAccess SQL查询查找最近的日期> 180过去

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,APPEARED DATE。我试图找到的是相同的产品(具有相同的CTY,CAT,OWN,BRD,EXT,APPEARED DATE)是否在过去推出了180次或更多。所以我需要一个Previous Date列(> 180列),它会显示ATTR ='NEW'过去的最早日期> 180。

我已经做了一个左连接,以获取表中的所有行(32行,但只获得25)。在无法确定先前日期的情况下,我无法添加NULL。 [请参见Sample.xlsx中的Query_Based表单)。

如何向y。[出现日期]列(即上一个日期列)添加空格或NULL?有没有更好的和有效的方式来写这个查询?

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

+1

从技术上讲,这个问题不应该说“(具有相同的CTY,CAT,OWN,BRD,EXT,出现DATE)推出180以上...“,因为不可能有相同的APPEARED日期,并在不同的时间启动。它应该说“(具有相同的CTY,CAT,OWN,BRD,EXT)发射180或更多......” –

+1

该文本说“启动180或更多”,这意味着> = 180而不是> 180。否则它应该说“推出超过180”。那它是哪一个?顺便说一句,也许“天”是隐含的,但正如我所教,并一直传递给我的学生 - 总是包括单位。 :) –

回答

1

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

原始查询和对方的回答正在从根本上选择错误:内部查询是选择每个键,即MIN([appeared date])只有一个日期,但最近的“发射”日期(> 180天)有不同的变化相同密钥的值为[appeared date]。因此,子查询必须在选择最近启动日期之前应用日期条件。换句话说,条件“> 180天”必须应用于Max([appeared date])表达式和相应的分组之前。 (仅供参考:由于在集合操作之前应用了连接条件,因此在同一查询中同时满足正确的申请顺序就足够了)。

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

  1. 如果条件TEMP.[Attr] = "New"是在同一个查询应用(例如,在WHERE子句中),这将排除在左侧返回NULL行的可能性-join,所以最终结果将只包含具有非空“发布日期> 180天”的行。到目前为止,这是25行而不是完整32的原因。
  2. 访问要求每个连接操作包括来自每个表的列,因此不允许使用类似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); 

注:表[温度]在每个子查询别名不同,以避免与访问解析到同一个表中引用的任何可能出现的问题不同的子查询。

下面是使用参数化的子查询等价查询的替代,但:

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; 
+1

是的...... C帕金斯在这里详细介绍了细节。让子查询正确是这个问题的挑战。由于我只是想指出方向,没有时间去适当的细节级别,所以我会删除我的回复。做得好! :) – abraxascarab

+0

@abraxascarab我发现你的回答非常丰富,所以不知道你为什么删除它们。但非常感谢您的帮助。 – sifar786