【问题标题】:How do I prevent duplicates from a SQL join?如何防止 SQL 连接出现重复?
【发布时间】:2021-08-06 02:18:43
【问题描述】:

我有以下表格:

customer:

id customer_number company firstname lastname account_manager_email email comments terms tax_id_number lead_source default_catalog credit_limit
99453 C00123456 Serenity Inc. Malcom Reynolds jim.smith@example.com mal@example.com The cap'n 1 NULL NULL 12345 NULL
99468 C00123456 Serenity Inc. Zoe Washburne jim.smith@example.com zoe@example.com NULL 1 NULL NULL NULL NULL
99960 C00123456 Serenity Inc. Hoban Washburne jim.smith@example.com wash@example.com NULL 1 NULL NULL NULL NULL
100088 C00123456 Serenity Inc. Inara Serra jim.smith@example.com inara@example.com NULL 1 NULL NULL 12345 NULL

customer_address:

id company street city state_abbreviation postcode telephone firstname lastname created_at
133996 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 Malcom Reynolds 2017-05-08 12:45:53.000
134452 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 Accounts Payable 2017-05-09 10:19:59.000
134961 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 REF 987654321 2017-05-09 10:19:59.000
134962 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 REF 192837465 2017-05-09 10:19:59.000
133995 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 Accounts Payable 2017-05-09 10:19:59.000
133669 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 REF 123456789 2017-05-18 10:29:42.000
133667 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 Accounts Payable 2017-05-18 07:56:45.000
133666 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 Accounts Payable 2017-05-31 07:56:46.000
133626 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 Accounts Payable 2017-06-16 12:45:08.000
133668 Serenity, Inc 123 Any St. Anytown AX 12345 123-456-7890 REF PO 2017-06-16 12:45:08.000

我正在运行此查询以生成可用于将数据导入另一个系统的 CSV:

     SELECT '"' + CAST(c.customer_number AS VARCHAR) + '"' AS 'Customer Number',
            '"' + CAST(c.company AS VARCHAR) + '"' AS 'Company Name',
            '"' + CAST(a.street AS VARCHAR) + '"' AS 'Company Address Line 1',
            '"' + CAST(a.city AS VARCHAR) + '"' AS 'Company City',
            '"' + CAST(a.state_abbreviation AS VARCHAR) + '"' AS 'Company State',
            '"' + CAST(a.postcode AS VARCHAR) + '"' AS 'Company Zip Code',
            '"' + CAST(a.telephone AS VARCHAR) + '"' AS 'Company Phone',
            '"' + CAST(c.firstname AS VARCHAR) + '"' AS 'Contact First Name',
            '"' + CAST(c.lastname AS VARCHAR) + '"' AS 'Contact Last Name',
            '"' + CAST(c.account_manager_email AS VARCHAR) + '"' AS 'Account Manager Email',
            '"' + CAST(a.company AS VARCHAR) + '"' AS 'Contact Company Name',
            '"' + CAST(a.street AS VARCHAR) + '"' AS 'Contact Address Line 1',
            '"' + CAST(a.city AS VARCHAR) + '"' AS 'Contact City',
            '"' + CAST(a.state_abbreviation AS VARCHAR) + '"' AS 'Contact State',
            '"' + CAST(a.postcode AS VARCHAR) + '"' AS 'Contact Zip Code',
            '"' + CAST(a.telephone AS VARCHAR) + '"' AS 'Contact Phone',
            '"' + CAST(c.email AS VARCHAR) + '"' AS 'Contact Email',
            '"' + CAST(c.comments AS VARCHAR) + '"' AS 'Internal Notes',
            '"' + CAST(c.terms AS VARCHAR) + '"' AS 'Terms',
            '"' + CAST(c.tax_id_number AS VARCHAR) + '"' AS 'Tax ID (US)',
            '"' + CAST(c.lead_source AS VARCHAR) + '"' AS 'Lead Source',
            '"' + CAST(c.default_catalog AS VARCHAR) + '"' AS 'Catalog',
            '"' + CAST(c.credit_limit AS VARCHAR) + '"' AS 'Credit Limit'
       FROM customer c,
            customer_address a
      WHERE c.customer_number = 'C00123456'
        AND a.company = c.company
   ORDER BY c.customer_number,
            c.created_at;

但是,当我运行该查询时,我得到了 40 行,customer 中的每个条目有 10 行。我尝试了不同的连接类型,但结果是一样的。

其中很多是遗留数据,所以我似乎唯一能够可靠地加入的是公司名称(“Serenity, Inc.”)

我实际上需要这个输出的两个版本。第一个是每个公司的单行,其中包含customer 表中具有最旧created_at 值的条目。第二个是所有其他记录。

注意:这是在 SQL Server 2005 上(我知道...计划升级,但我必须先完成这个)

【问题讨论】:

  • 您确定不能可靠地加入 fristname 和 lastname 吗?我回答说这两列看起来像是导致你的重复,但现在我很好奇为什么你不能使用这两列?如果你不能可靠地使用它们,你将不得不创造性地逐步按摩,以弄清楚如何正确地做到这一点。我还假设您不需要“应付账款”的记录?
  • 您有 4 行连接到 10 行的匹配值,所以当然 4x10=40。您的Customers 表没有created_at,它在您的customers_address 中。如果你只想要一行,大概是最小客户Id
  • 您还尝试了哪些其他联接?可能值得学习 SQL 基础知识,例如在以下站点:w3schools.com/sql/sql_join.asp
  • customer_address 应该有一个 customer_id 列,它是将每个 customer_address 与一个 customer 相关联的外键。为什么不呢?
  • @DavidBrowne-Microsoft 我同意并希望我能得到这个问题的答案,但不幸的是,我没有。

标签: sql-server sql-server-2005


【解决方案1】:

要删除重复项,您需要枚举每一行并根据排序条件分配一个值。

您可以使用cte 轻松做到这一点 - 我相信它们在 SQL Server 2005 中可用,我当然无法检查。

with c as(
  select *, Row_Number() over(partition by customer_number order by id) rn
  from customer
),
ca as (
  select *, Row_Number() over(partition by company order by created_at) rn
  from customer_address
)
select <columns>
from c join ca on c.company=ca.company
where c.rn=1 and ca.rn=1 and c.customer_number='C00123456'

【讨论】:

    【解决方案2】:

    您还尝试了哪些其他联接?

    这是为每个客户记录选择最近的 customer_address 记录的一种方法:

    SELECT c.*, a.* FROM
    customer c
    LEFT JOIN 
      ( SELECT x.* FROM customer_address x
        INNER JOIN 
        (SELECT company, MAX(created_at) AS created_at FROM customer_address 
           GROUP BY company) u
        ON u.company=x.company AND u.created_at=x.created_at
      ) a
    ON a.company=c.company
    WHERE c.customer_number = 'C00123456';
    

    因此,所有其他 customer_address 记录将由:

      ( SELECT x.* FROM customer_address x
        INNER JOIN 
        (SELECT company, MAX(created_at) AS created_at FROM customer_address 
           GROUP BY company) u
        ON u.company=x.company AND NOT u.created_at=x.created_at
      ) a
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-31
      • 1970-01-01
      相关资源
      最近更新 更多