【问题标题】:LEFT JOIN not keeping only records that occur in a SELECT queryLEFT JOIN 不只保留 SELECT 查询中出现的记录
【发布时间】:2021-02-15 17:25:27
【问题描述】:

我有以下 SQL 选择语句,用于获取产品或葡萄酒的子集:

SELECT pv.SkProdVariantId AS id,
       pa.Colour AS colour,
  FROM Dim.ProductVariant AS pv
  JOIN ProductAttributes_new AS pa
    ON pv.SkProdVariantId = pa.SkProdVariantId
 WHERE pv.ProdTypeName = 'Wines'

生成的这个表的长度是 3,905。我想获取这些产品的所有交易数据。 目前我正在使用这个 select 语句

SELECT c.CalDate AS timestamp,
       f.SkProductVariantId AS sku_id,
       f.Quantity AS quantity
  FROM fact.FTransactions AS f
LEFT JOIN Dim.Calendar AS c
          ON f.SkDateId = c.SkDateId
LEFT JOIN (    
  SELECT pv.SkProdVariantId AS id,
         pa.Colour AS colour,
    FROM Dim.ProductVariant AS pv
    JOIN ProductAttributes_new AS pa
      ON pv.SkProdVariantId = pa.SkProdVariantId
   WHERE pv.ProdTypeName = 'Wines'  
  ) AS s
  ON s.id = f.SkProductVariantId
 WHERE c.CalDate LIKE '%2019%'

日历日期正确,但返回的独特产品数量为 5,648,而不是 select 查询中预期的 3,905。

为什么我在第一个选择查询中的LEFT JOIN 没有像我预期的那样工作?

感谢您的帮助!

【问题讨论】:

  • 如果连接中匹配的行数> 1,则左连接将重复行
  • @Charlieface 这就是我所期望的,因为可能有许多交易与一种产品相关联。但是,我看到第二个表中有更多的唯一 SKU ID,而第一个表中肯定是不正确的?
  • 您正在选择 2019 年的所有交易。LEFT JOIN Dim.Calendar 确实是 INNER JOIN Dim.Calendar,因为使用 WHERE c.CalDate LIKE '%2019%' 您可以忽略所有外部连接行(如果存在,我对此表示怀疑)。然后你外部加入葡萄酒信息。结果,您将获得 2019 年的所有交易,而葡萄酒交易将获得额外的葡萄酒信息。

标签: sql sql-server join


【解决方案1】:

如果您希望查询中的所有行,它必须是LEFT JOIN 中的first 引用。那么,我猜你想在 2019 年进行交易:

select . . .
from (SELECT pv.SkProdVariantId AS id, pa.Colour AS colour,
      FROM Dim.ProductVariant pv JOIN
           ProductAttributes_new pa
           ON pv.SkProdVariantId = pa.SkProdVariantId
      WHERE pv.ProdTypeName = 'Wines'
     ) s LEFT JOIN
     (fact.FTransactions f JOIN
      Dim.Calendar c
      ON f.SkDateId = c.SkDateId AND
         c.CalDate >= '2019-01-01' AND
         c.CalDate < '2020-01-01'
     )
     ON s.id = f.SkProductVariantId;

请注意,这假定CalDate 确实是日期而不是字符串。 LIKE 只能用于字符串。

【讨论】:

  • 那一定是我出错的地方,我会尽快尝试...谢谢!
【解决方案2】:

您以某种方式误解了外部联接的工作原理。请参阅 Gordon 的回答和我对此的请求评论。

关于任务:您似乎想选择 2019 年的交易,但您想将结果限制在葡萄酒产品上。我们通常在WHERE 子句中限制查询结果。为此,您可以使用IN 或EXISTS。

SELECT
  c.CalDate AS timestamp,
  f.SkProductVariantId AS sku_id,
  f.Quantity AS quantity
FROM fact.FTransactions AS f
INNER JOIN Dim.Calendar AS c ON f.SkDateId = c.SkDateId
WHERE DATEPART(YEAR, c.CalDate) = 2019
AND f.SkProductVariantId IN
(
  SELECT pv.SkProdVariantId
  FROM Dim.ProductVariant AS pv
  WHERE pv.ProdTypeName = 'Wines'
);

(我已删除到 ProductAttributes_new 的连接,因为它似乎在此查询中没有任何作用。)

【讨论】:

  • 感谢您的帮助并澄清几点。
猜你喜欢
  • 2015-02-22
  • 2012-09-05
  • 2019-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-27
  • 2014-09-27
  • 1970-01-01
相关资源
最近更新 更多