SQL:为什么 distinct 和 max 不删除重复项?
SQL: Why is distinct and max not removing 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 将其加入原始 table,以获得最新的租户类型。
为什么它仍然返回重复的行!?
(顺便说一下,这与我昨天遇到的另一个问题有关,但显然回复不应该进入对话,所以我想我会把它分开......我希望这是正确的做法...我已经搜索过了,但显然我对某些东西的理解缺少了一些东西!)
首先,使用 group by
时几乎不需要 select distinct
。
您的查询的问题是子查询中的 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
。此外,您的外部查询在 group by
.
中有两次 ACC.TenancyType
也就是说,使用解析函数编写查询更容易:
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;
这与您的查询完全不一样,因为您的查询将考虑非当前记录。不过,我猜这可能是故意的。
回答你的问题:是的,你是对的,不能重复。而且我很确定有 none。我也很确定你的查询并不像你想象的那样。
这是你的派生table:
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 不同记录的不同记录。您的子查询可以重写为:
SELECT DISTINCT PropertyID, TenancyStartDate
FROM DimAccount
WHERE AccountStatus = 'Current'
然后您外部加入 DimAccount table。因此,即使没有匹配的 DimAccount 记录,您也会保留找到的记录。但是:您 select 从 DimAccount 编辑过,所以当然总是至少有一条您已经找到的记录。您的外部联接实际上是内部联接。然后派生查询中显示的唯一字段是 PropertyID,它始终等于 ACC.PropertyID。这意味着:您只是 selecting 来自 ACC 的记录,派生的 table 只是为了确保 PropertyID 和 TenancyStartDate 的 'Current' 记录 存在 .因此,您的查询可以重写为:
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 是 table 的 ID 吗?)那么您甚至可以删除 DISTINCT。
此查询首先获取所有 'Current' DimAccount 记录,然后为您提供具有相同 PropertyID 和 TenancyStartDate 的所有记录。但是,根据您的解释,您似乎想要 select latest 'Current' 每个 PropertyID 的 DimAccount 记录。这完全是另外一回事。根据您使用的 dbms(您没有在标签中指定您的),此类任务有不同的解决方案。
下面的查询是否应该删除重复项:
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 将其加入原始 table,以获得最新的租户类型。
为什么它仍然返回重复的行!?
(顺便说一下,这与我昨天遇到的另一个问题有关,但显然回复不应该进入对话,所以我想我会把它分开......我希望这是正确的做法...我已经搜索过了,但显然我对某些东西的理解缺少了一些东西!)
首先,使用 group by
时几乎不需要 select distinct
。
您的查询的问题是子查询中的 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
。此外,您的外部查询在 group by
.
ACC.TenancyType
也就是说,使用解析函数编写查询更容易:
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;
这与您的查询完全不一样,因为您的查询将考虑非当前记录。不过,我猜这可能是故意的。
回答你的问题:是的,你是对的,不能重复。而且我很确定有 none。我也很确定你的查询并不像你想象的那样。
这是你的派生table:
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 不同记录的不同记录。您的子查询可以重写为:
SELECT DISTINCT PropertyID, TenancyStartDate
FROM DimAccount
WHERE AccountStatus = 'Current'
然后您外部加入 DimAccount table。因此,即使没有匹配的 DimAccount 记录,您也会保留找到的记录。但是:您 select 从 DimAccount 编辑过,所以当然总是至少有一条您已经找到的记录。您的外部联接实际上是内部联接。然后派生查询中显示的唯一字段是 PropertyID,它始终等于 ACC.PropertyID。这意味着:您只是 selecting 来自 ACC 的记录,派生的 table 只是为了确保 PropertyID 和 TenancyStartDate 的 'Current' 记录 存在 .因此,您的查询可以重写为:
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 是 table 的 ID 吗?)那么您甚至可以删除 DISTINCT。
此查询首先获取所有 'Current' DimAccount 记录,然后为您提供具有相同 PropertyID 和 TenancyStartDate 的所有记录。但是,根据您的解释,您似乎想要 select latest 'Current' 每个 PropertyID 的 DimAccount 记录。这完全是另外一回事。根据您使用的 dbms(您没有在标签中指定您的),此类任务有不同的解决方案。