SQL:为什么distinct和max不能删除重复项?

时间:2015-03-24 10:37:14

标签: sql visual-studio duplicates

以下查询删除重复项:

SELECT DISTINCT Relevant.PropertyID, ACC.TenancyStartDate, ACC.AccountID, ACC.TenancyType
FROM            DimAccount AS ACC RIGHT OUTER JOIN
                             (SELECT DISTINCT PropertyID, MAX(TenancyStartDate) AS Tenancystart
                               FROM            DimAccount
                               WHERE        (AccountStatus = 'Current')
                               GROUP BY PropertyID, TenancyStartDate) AS Relevant ON ACC.PropertyID = Relevant.PropertyID AND ACC.TenancyStartDate = Relevant.Tenancystart
GROUP BY Relevant.PropertyID, ACC.TenancyStartDate, ACC.AccountID, ACC.TenancyType, ACC.TenancyType

根据我的理解(以及我想要发生的事情),括号中的查询是选择属性ID以及状态为当前返回最高租期开始日期(尽管数次)的属性ID。然后通过开始日期和属性id将其连接到原始表,以获取最新的租赁类型。

为什么它仍然会返回重复的行!?

(顺便说一句,这与我昨天的另一个问题有关,但显然回复不应该进入对话,所以我想我会把它分开......我希望这是正确的做法......我已经搜索过但很明显我对某些事物的理解缺少了一些东西!)

2 个答案:

答案 0 :(得分:0)

首先,使用select distinct时几乎不需要group by

查询的问题是子查询中的group by子句。

SELECT Relevant.PropertyID, ACC.TenancyStartDate, ACC.AccountID, ACC.TenancyType
FROM DimAccount ACC RIGHT OUTER JOIN
     (SELECT PropertyID, MAX(TenancyStartDate) AS Tenancystart
      FROM  DimAccount
      WHERE (AccountStatus = 'Current')
      GROUP BY PropertyID
    ) Relevant
     ON ACC.PropertyID = Relevant.PropertyID AND
        ACC.TenancyStartDate = Relevant.Tenancystart
GROUP BY Relevant.PropertyID, ACC.TenancyStartDate, ACC.AccountID, ACC.TenancyType;

它不应该有TenancyStartDate。此外,您的外部查询在ACC.TenancyType中有两次group by

也就是说,使用分析函数编写查询更容易:

select a.*
from (select a.*,
             max(tenancystartdate) over (partition by propertyid) as max_tsd
      from dimaccount a
      where accountstatus = 'Current'
     ) a
where tenancystartdate = max_tsd;

与您的查询完全相同,因为您的查询会考虑非当前记录。但我猜这可能是出于此目的。

答案 1 :(得分:0)

回答你的问题:是的,你是对的,没有重复。而且我很确定没有。我也很确定你的查询不符合你的想法。

这是你的派生表:

SELECT DISTINCT PropertyID, MAX(TenancyStartDate) AS Tenancystart
FROM            DimAccount
WHERE        (AccountStatus = 'Current')
GROUP BY PropertyID, TenancyStartDate

当您按PropertyID和TenancyStartDate进行分组时,每个PropertyID和TenancyStartDate会获得一行。对于每个这样的行,您需要MAX(TenancyStartDate),当然这是TenancyStartDate本身。您没有聚合的其他字段,因此您根本不进行聚合,而只是使行不同,对于哪个行将使用DISTINCT。然后你使用DISTINCT获取唯一的结果记录,但是你的记录已经是独一无二的,你的模糊方式就是这样做了。所以你说:选择不同记录的不同记录。您的子查询可以重写为:

SELECT DISTINCT PropertyID, TenancyStartDate
FROM DimAccount
WHERE AccountStatus = 'Current'

然后你外连接DimAccount表。因此,即使没有匹配的DimAccount记录,您也会保留已找到的记录。但是:你从DimAccount中选择了,所以当然至少有一个你已经找到的记录。您的外部联接实际上是内部联接。然后,显示的派生查询中唯一的字段是PropertyID,它始终等于ACC.PropertyID。这意味着:您只是从ACC中选择记录,而派生表只是为了确保PropertyID和TenancyStartDate的“当前”记录存在。因此,您的查询可以重写为:

SELECT DISTINCT 
  PropertyID, TenancyStartDate, AccountID, TenancyType
FROM DimAccount AS ACC 
WHERE EXISTS
(
  SELECT *
  FROM DimAccount CurrentAccount
  WHERE CurrentAccount.AccountStatus = 'Current'
  AND CurrentAccount.PropertyID = ACC.PropertyID
  AND CurrentAccount.TenancyStartDate = ACC.TenancyStartDate
);

如果PropertyID + TenancyStartDate + AccountID + TenancyType是唯一的(AccountID是表的ID?),那么您甚至可以删除DISTINCT。

此查询首先获取所有“当前”DimAccount记录,然后为您提供具有相同PropertyID和TenancyStartDate的所有记录。但是,根据您的解释,您似乎想要为每个PropertyID选择最新'当前'DimAccount记录。这完全不同于此。这种任务有不同的解决方案,具体取决于您使用的dbms(您没有在标签中指定自己的。)