【问题标题】:Selecting distinct records without using a temporary table在不使用临时表的情况下选择不同的记录
【发布时间】:2011-08-15 21:28:29
【问题描述】:

我有一个第三方表,其中填充了一些杂乱的数据,我需要从中获取最新的不同记录。每年或每次“Person”更改时,都会为该表提供一个新行。该表的工作基于最近的 ActiveDate 是正确的人。我创建了一个模拟表和数据来展示这一点。

CREATE TABLE `Persons` (
  `PersonId` varchar(200) NOT NULL,
  `Name` varchar(200) NOT NULL DEFAULT '',
  `ActiveDate` varchar(25) NOT NULL,
  `ExpireDate` varchar(25) DEFAULT NULL,
  `Job` varchar(200) NOT NULL DEFAULT '',
  `Position` varchar(200) NOT NULL DEFAULT ''
)

还有一些模拟数据:

Id       |`Name`        |ActiveDate              |ExpireDate             |Job       |`Position`
---------------------------------------------------------------------------------------------------
J1234    |Doe, John     |2010-08-15 00:00:00     |2011-08-15 00:00:00    |Worker    |Janitor
J1234    |Doe, John     |2011-08-15 00:00:00     |0000-00-00 00:00:00    |Worker    |Janitor
777      |Doe, Jane     |2010-06-04 00:00:00     |0000-00-00 00:00:00    |Boss      |Janitor
777      |Doe, Jane     |2011-04-30 00:00:00     |0000-00-00 00:00:00    |Boss      |Janitor
654G     |Smith, Jane   |2011-01-20 00:00:00     |0000-00-00 00:00:00    |Worker    |Janitor

该表还有 ExpireDate 列,该列实际上是由最终用户设置的,并不总是让我感到沮丧。目前我正在使用一个虚拟表将不同的记录拉出来并存储一天。我会使用临时表,但我不是 100% 确定如何在 MySQL 中使用,而且我不喜欢它们。我这样做的方式只是暂时的,希望有更好的 SQL。

然后必须将数据与大量其他表连接起来才能获得最终产品。但是我仍然需要处理最初的一组不同的数据。从一开始就加入另一张桌子是行不通的。

这就是我提取数据、存储数据、稍后再提取数据并将其连接到其他表的方式:

INSERT INTO tmp_Person (Id, `Name`, Job, `Position`) 
    SELECT DISTINCT Id, `Name`, Job, `Position`
    FROM Person 

SELECT  tmp_Person.Id, 
    tmp_Person.`Name`, 
    tmp_Person.Job, 
    tmp_Person.`Position`,
    Pricing.Cost, 
    Pricing.Benefit

    FROM tmp_Person
    LEFT OUTER JOIN Pricing AS CL ON CL.PersonId = tmp_Person.Id 
        AND CL.PriceScredule = 'Major-Client' 
        AND CL.ExpireDate = '0000-00-00 00:00:00'
    LEFT OUTER JOIN Pricing AS Inter ON Inter.PersonId = tmp_Person.Id 
        AND Inter.PriceScredule = 'Internal-Client' 
        AND Inter.ExpireDate = '0000-00-00 00:00:00'

如何编写此代码以避免使用临时表(以任何形式)处理重复行的成本?希望我已经说得够清楚了,如果不是,我可以很高兴地补充或澄清。

【问题讨论】:

  • 是否可以有两行具有相同的Id,但NameJobPosition 不同?如果没有,查询可能会更优化。
  • 不,Id 实际上是我数据中的唯一列。它也适用于这个其他数据库,只是不在这个数据中。我正在从第三方计费系统中挖掘数据,他们只是每天向我们发送这个永无止境的数据流。然后我钓鱼并取出我们需要的东西。我正在尝试维护一个充满怪异的遗留系统,其中包含来自第三方的数据,其中充满了更多的怪异。全部用我的代码,希望......不是奇怪的。
  • 也许您不应该加入Pricing 表两次,因为这样您就可以使用Pricing 别名(前提是它不会被更改)。事实上,您不能在 SELECT 子句中引用 Pricing,它应该是 CLInter
  • 我相信单连接版本的组合条件可能是Pricing.PersonId = tmp_Person.Id AND Pricing.PriceScredule IN ('Major-Client', 'Internal-Client') AND Pricing.ExpireDate = '0000-00-00 00:00:00'
  • 您说“最近的 ActiveDate 是正确的人”,那么为什么不将这些记录插入到临时表中呢?换句话说,您确定采用不同的记录会得到相同的结果吗?

标签: mysql sql data-processing


【解决方案1】:

tmp_Person 替换为临时表的代码:

SELECT  tmp_Person.Id, 
    tmp_Person.`Name`, 
    tmp_Person.Job, 
    tmp_Person.`Position`,
    CL.Cost     AS MajorCost,              
    CL.Benefit  AS MajorBenefit,   
    Inter.Cost    AS InternalCost,
    Inter.Benefit AS InternalBenefit

    FROM 
      ( SELECT DISTINCT Id, `Name`, Job, `Position`
        FROM Person 
      )
      AS tmp_Person
    LEFT OUTER JOIN Pricing AS CL ON CL.PersonId = tmp_Person.Id 
        AND CL.PriceScredule = 'Major-Client' 
        AND CL.ExpireDate = '0000-00-00 00:00:00'
    LEFT OUTER JOIN Pricing AS Inter ON Inter.PersonId = tmp_Person.Id 
        AND Inter.PriceScredule = 'Internal-Client' 
        AND Inter.ExpireDate = '0000-00-00 00:00:00'

正如@Andriy 所发现的,在 SELECT 列表中使用 Pricing.CostPricing.Benefit 会引发错误。我猜你发帖的时候忘记改了。

【讨论】:

  • 我将在早上尝试这个。肯定会节省更多时间。随着数据库的老化(希望是优雅的),甚至更多。
  • 您通过引用 Pricing 而不是 CLInter(在 SELECT 子句中)来复制 OP 的错误。
  • @Andriy:Thnx,没注意到。
  • @Andriy M:说得很好。想一想:为什么外连接到两个表却不在SELECT 子句(或其他任何地方)中使用它们的列?
  • @onedaywhen:他可能试图简化在此处发布的查询。我可以通过在 SELECT 列表中看到数十列发布的查询来理解这一点。
【解决方案2】:

在我意识到问题是针对 mysql 但主体应该相同之前将其放在一起,这将为您获取每个 PersonID 的记录以及来自 Person 表的最新 ActiveDate。

select *
from
(
 select persons.*, ROW_NUMBER() over(partition by personid order by personid, activedate desc) as rn 
 from persons
) basedata
where basedata.rn=1

【讨论】:

  • 不幸的是 MySQL 没有 ROW_NUMBER()OVER()。根本没有分析函数。
猜你喜欢
  • 2011-10-02
  • 1970-01-01
  • 2018-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-27
  • 1970-01-01
相关资源
最近更新 更多