【问题标题】:Self join and inner join to remove duplicates自联接和内部联接以删除重复项
【发布时间】:2019-01-26 00:57:04
【问题描述】:

我被困在这个问题上,而且我对 SQL 还比较陌生。

这是我们收到的问题:

列出我们拥有的所有产品的产品名称和供应商 ID 从多个供应商处购买(提示:您需要一个 Self-Join 和 一个额外的 INNER JOIN 来解决,不要忘记删除任何 重复!!)

这是我们正在使用的表格的屏幕截图:

这就是我所拥有的......我知道这是错误的。它在一定程度上起作用,只是不完全是教授想要的。

SELECT DISTINCT productname, product_vendors.vendorid 
FROM products INNER JOIN Product_Vendors
ON products.PRODUCTNUMBER = PRODUCT_VENDORS.PRODUCTNUMBER
INNER JOIN vendors ON Product_Vendors.VENDORID = vendors.VENDORID
ORDER BY products.PRODUCTNAME;

提供教授的预期输出:

【问题讨论】:

  • 指定示例表数据和预期结果 - 以及格式化文本。
  • 我可能会使用 COUNT() 进行 GROUP BY。
  • 嗨 Mike,我们只应该在这个练习中使用 INNER JOIN。
  • 这里根本不需要 LEFT JOIN。
  • 内联同一张表两次,确保不同厂商!

标签: sql oracle


【解决方案1】:

我同意@jarlh 的观点,即额外的信息会有所帮助 - 即数据中是否存在三次重复或只是重复等。

也就是说,这应该让你开始

SELECT
    c.productname   AS 'Product'
    ,a.vendorid     AS 'Vendor1'
    ,b.vendorid     AS 'Vendor2'

FROM
    product_vendors AS a
JOIN 
    product_vendors AS b
        ON 
        a.productnumber = b.productnumber
        AND a.vendorid <> b.vendorid
JOIN
    dbo.products AS c
        ON
        a.productnumber = c.productnumber

这会将“产品供应商”的数量限制在具有不匹配供应商的产品上。 从那里您将加入产品以撤回产品名称。

还致力于编码格式,干净的代码使梦想成真:)

【讨论】:

  • 使用适当的别名会更好,例如p 用于产品,v1v2 用于产品供应商。
【解决方案2】:

解决此问题的方法通常是使用COUNT OVER 计算每个产品的供应商,并且只坚持使用多个产品的产品。简单地说:

select productname, vendorid
from
(
  select 
    p.productname, 
    pv.vendorid, 
    count(*) over (partition by product) as cnt
  from products p
  join product_vendors pv using (productnumber)
)
where cnt > 1;

如果这应该在没有窗口函数的情况下完成,那么一种选择是聚合 product_vendors 并使用此结果:

select p.productname, pv.vendorid
from
(
  select productid 
  from product_vendors
  group by productname
  having count(*) > 1
) px
join products p using (productid)
join product_vendors pv using (productid);

或检查该产品是否存在其他供应商:

select 
  p.productname, 
  pv.vendorid, 
  count(*) over (partition by product) as cnt
from products p
join product_vendors pv on pv.productnumber = p.productnumber
where exists
(
  select *
  from product_vendors other
  where other.productnumber = pv.productnumber
  and other.vendorid <> pv.vendorid
);

在这两种方法中,我都认为没有必要消除重复,因为products 中的每个产品应该有一行,product_vendors 中每个产品和供应商应该有一行。所以我猜你的教授的想法是:

select distinct
  p.productname, 
  pv.vendorid
from products p
join product_vendors pv on pv.productnumber = p.productnumber
join product_vendors other on other.productnumber = pv.productnumber
                           and other.vendorid <> pv.vendorid

但是,我不推荐这种方法。您可以将产品的所有供应商组合在一起(例如,如果我没记错的话,一个产品的 10 个供应商已经有该产品的 45 个组合)。因此,您将创建一个较大的中间结果,但稍后会使用DISTINCT 来消除其中的大部分。不要那样做。请记住:SELECT DISTINCT 通常表示查询编写不当(即不必要的连接会导致您实际上不感兴趣的组合过多)。

【讨论】:

    【解决方案3】:
    SELECT DISTINCT p.name AS product, v.id
    FROM products p 
         INNER JOIN product_vendors pv ON p.id = pv.productid
         INNER JOIN product_vendors pv2 ON pv.productid = pv2.productid AND pv.vendorid != pv2.vendorid 
         INNER JOIN vendors v ON v.id = pv.vendorid
    ORDER BY p.name
    

    【讨论】:

    • 请在您的答案中添加描述。你的代码是做什么的
    猜你喜欢
    • 1970-01-01
    • 2017-12-22
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 2017-11-03
    • 1970-01-01
    • 1970-01-01
    • 2019-01-20
    相关资源
    最近更新 更多