Mysql 如何使用左外联接按供应商识别缺少的产品?

Mysql 如何使用左外联接按供应商识别缺少的产品?,mysql,sql,join,left-join,outer-join,Mysql,Sql,Join,Left Join,Outer Join,这个问题很有趣,但我来到了需要帮助的地方 我有几个表格,最终的问题是: 供应商提供的“缺失”零件总数是多少 和/或 按供应商和类别列出的“缺失”零件总数是多少 缺失:未被供应商使用(参见查询1) 请注意,零件不属于某个产品或供应商,因为这两种产品或供应商可能会根据季节而变化,而且零件通常会激发出产品的实际价值 基本上,每个供应商都知道哪些部分是我们试图在较高层次上回答的问题,以确定哪些供应商缺少的零件最多,哪些类别的零件缺少 现在,我有了我需要的第一个问题,非常好。当我指定特定的供应商时

这个问题很有趣,但我来到了需要帮助的地方

我有几个表格,最终的问题是:

  • 供应商提供的“缺失”零件总数是多少
和/或

  • 按供应商和类别列出的“缺失”零件总数是多少
缺失:未被供应商使用(参见查询1)

请注意,零件不属于某个产品或供应商,因为这两种产品或供应商可能会根据季节而变化,而且零件通常会激发出产品的实际价值

基本上,每个供应商都知道哪些部分是我们试图在较高层次上回答的问题,以确定哪些供应商缺少的零件最多,哪些类别的零件缺少

现在,我有了我需要的第一个问题,非常好。当我指定特定的供应商时,它会按类别告诉我缺少的零件

以下是数据库的创建脚本和工作查询的SQLFIDLE:

问题1:

以及查询:

SELECT 
    c.name AS category,
    COUNT(pt.id) AS parts,
    COUNT(CASE WHEN in_stock IS NULL THEN pt.id END) AS missing_parts
FROM 
    season AS s
LEFT OUTER JOIN 
    ( 

        SELECT 
            s.id AS season_id,
            s.type season_type,
            max(i.in_stock) AS in_stock
        FROM
            inventory AS i
            JOIN season      AS s  ON i.season_id = s.id
            JOIN product     AS p  ON i.product_id = p.id
            JOIN vendor      AS v  ON p.vendor_id = v.id
            JOIN part        AS pt ON s.part_id = pt.id

        WHERE
            v.id = 2
            AND
            s.type = 'Type A'
        GROUP BY
            1,2) AS seas   ON seas.season_id = s.id AND seas.season_type = s.type
            JOIN part      AS pt ON pt.id = s.part_id
            JOIN part_data AS pd ON pt.id = pd.part_id
            JOIN category  AS c  ON pt.category_id = c.id
    WHERE
        s.type = 'Type A'
GROUP BY
    1;
上面的工作就像一个魅力,以下是结果:

| name      | parts | missing_parts |
|-----------|-------|---------------|
| category3 | 3     | 2             |
| category4 | 2     | 0             |
| category5 | 2     | 2             |
| category6 | 3     | 3             |
我的问题是,当我尝试使用vendor而不是category执行类似的查询时,同时删除vendor过滤器。在下面的SQL FIDLE中,您可以看到,由于零件实际上缺失,所以在像我这样进行查询时,它们当然不能归因于供应商

他们的问题2:

SELECT 
    seas.vendor AS vendor,
    COUNT(pt.id) AS parts,
    COUNT(CASE WHEN in_stock IS NULL THEN pt.id END) AS missing_parts 
FROM 
    season AS s
LEFT OUTER JOIN     
 (SELECT 
            s.id AS season_id,
            v.name AS vendor, 
            s.type season_type,
            max(i.in_stock) AS in_stock
        FROM
            inventory AS i
            JOIN season      AS s  ON i.season_id = s.id
            JOIN product     AS p  ON i.product_id = p.id
            JOIN vendor      AS v  ON p.vendor_id = v.id
            JOIN part        AS pt ON s.part_id = pt.id

        WHERE
            s.type = 'Type A'
        GROUP BY
            1,2          ) AS seas   ON seas.season_id = s.id AND seas.season_type = s.type
            JOIN part      AS pt     ON pt.id = s.part_id
            JOIN part_data AS pd     ON pt.id = pd.part_id
            JOIN category  AS c      ON pt.category_id = c.id

    AND
        s.type = 'Type A'
GROUP BY
    1;
查询2的结果:

| vendor   | parts | missing_parts |
|----------|-------|---------------|
| (null)   | 4     | 4             |
| Vendor 1 | 2     | 0             |
| Vendor 2 | 3     | 0             |
| Vendor 3 | 2     | 0             |
| Vendor 4 | 2     | 0             |
| Vendor 5 | 2     | 0             |
请注意空值,这是有意义的,因为这些是我正在寻找的不能归因于供应商的“缺失”零件

我想知道的是,是否有任何方法将缺少的零件计数添加到附加列中

期望输出中缺少的部分列很难精确,因为这也是这个查询的重点,我不知道…即使有这么少量的数据。再次注意,缺少的部件没有供应商,但这是我的最佳拍摄

| vendor   | parts | missing_parts |
|----------|-------|---------------|
| Vendor 1 | 2     | 1             |
| Vendor 2 | 3     | 1             |
| Vendor 3 | 2     | 3             |
| Vendor 4 | 2     | 0             |
| Vendor 5 | 2     | 2             | 
在理想情况下,我还可以添加类别:

| category   | vendor   | parts | missing_parts |
|------------|----------|-------|---------------|
| category 1 | Vendor 1 | 2     | 1             |
| category 1 | Vendor 2 | 3     | 1             |
| category 1 | Vendor 3 | 2     | 3             |
| category 1 | Vendor 4 | 2     | 0             |
| category 1 | Vendor 5 | 2     | 2             |
| category 2 | Vendor 1 | 1     | 1             |
| category 2 | Vendor 2 | 1     | 1             |
| category 2 | Vendor 3 | 0     | 3             |
| category 2 | Vendor 4 | 2     | 0             |
| category 2 | Vendor 5 | 0     | 2             |

问题是,第二个查询在子查询(
vendor
)中的一个字段上有一个
groupby
,该字段在
LEFT join
中连接,因此它将为每个供应商创建一个输出行(包括与子查询不匹配的季度行的
NULL

更具体地说,您的
计数已打开

作为缺失零件计数(库存为空时,则pt.id结束)

(我更喜欢写
总和(库存为空)

但由于
库存
是每个
供应商
的聚合结果,因此那里永远不会有
空值。()

我认为你应该澄清你提问的目的。例如,第一个正在返回-


每个类别在给定季节上的零件数量,以及该类别不可用的季节数量(而不是缺少零件的数量,因为没有与子查询的类别连接)。

如果我了解您在寻找什么,我首先从你最终想要的东西开始

不同部分和类别的列表。那么你是在寻找谁错过了什么。要做到这一点,这基本上是一个笛卡尔的每个供应商对这个“主列表的零件/类别”,谁没有/没有它

SELECT DISTINCT 
      pt.id, 
      pt.category_id
   from 
      part pt
SELECT DISTINCT 
      pt.id, 
      pt.category_id
   from 
      part pt

现在,考虑第二部分。特定供应商有哪些可能的零件和类别

SELECT DISTINCT 
      pt.id, 
      pt.category_id, 
      p.vendor_id
   FROM
      season s 
         JOIN inventory i
            ON s.id = i.season_id
            JOIN product p  
               ON i.product_id = p.id
         JOIN part pt 
            ON s.part_id = pt.id
SELECT DISTINCT 
      pt.id, 
      pt.category_id
   FROM
      season s 
         JOIN part pt 
            ON s.part_id = pt.id
   WHERE
      s.type = 'Type A'
在上面的表中,我不需要加入类别或实际的供应商表,因为我只关心谁拥有什么的合格ID。首先,所有可能的部件ID和类别ID,但在第二个中,我们还获取拥有它的供应商ID

现在,从加入类别的供应商开始,在没有任何“打开”条件的情况下,将这些零件绑在一起。该联接需要允许“v.id”作为语法中的较低联接,这将为我提供应用于/测试到每个类别的每个供应商的笛卡尔坐标。然后,类别表连接到所有不同的部件,最后左键连接到每个供应商的不同部件查询

最后,添加聚合和分组方式。由于左连接,如果存在VndParts.ID,则该记录确实存在,因此找到的供应商零件数增加。如果供应商零件id为空,则缺少缺少零件计数的零件id(因此我的sum case/when)

SELECT
      v.name Vendor,
      c.name  category,
      count( PQParts.ID ) TotalAvailableParts,
      count( VndParts.ID ) VendorParts,
      sum( case when VndParts.ID IS NULL then 1 else 0 end ) MissingParts
   from
      vendor v JOIN
      category c
         JOIN 
         ( SELECT DISTINCT 
                 pt.id, 
                 pt.category_id
              from 
                 part pt ) PQParts
            ON c.id = PQParts.category_id 
            LEFT JOIN
            ( SELECT DISTINCT 
                    pt.id, 
                    pt.category_id, 
                    p.vendor_id
                 FROM
                    season s 
                       JOIN inventory i
                          ON s.id = i.season_id
                          JOIN product p  
                             ON i.product_id = p.id
                       JOIN part pt 
                          ON s.part_id = pt.id ) VndParts
               ON v.id = VndParts.vendor_id
               AND PQParts.ID = VndParts.ID
               AND PQParts.Category_ID = VndParts.Category_ID
   group by
      v.name,
      c.name

现在,尽管您已经创建了类别1-6的示例数据,但您的所有零件都仅使用类别3-6进行定义,如我的示例数据结果中所示。我无法根据的示例查询强制获取不存在的数据

SELECT
      *
   from
      category c
         JOIN 
         ( SELECT DISTINCT 
                 pt.id, 
                 pt.category_id
              from 
                 part pt ) PQParts
            ON c.id = PQParts.category_id 
如果确实存在此类实际数据,则还将显示其他类别中缺失的部分

现在是最后一点。你也在寻找一个特定的季节。我只想在VndParts查询中添加一个WHERE子句来适应它。然后更改PQParts查询以包括季节联接,例如

现在,考虑第二部分。特定供应商有哪些可能的零件和类别

SELECT DISTINCT 
      pt.id, 
      pt.category_id, 
      p.vendor_id
   FROM
      season s 
         JOIN inventory i
            ON s.id = i.season_id
            JOIN product p  
               ON i.product_id = p.id
         JOIN part pt 
            ON s.part_id = pt.id
SELECT DISTINCT 
      pt.id, 
      pt.category_id
   FROM
      season s 
         JOIN part pt 
            ON s.part_id = pt.id
   WHERE
      s.type = 'Type A'

要进一步限制特定供应商,在中添加供应商子句非常简单,因为它是外部标准中供应商“v”的基础,以及对第二个左连接的供应商引用,该左连接还具有可过滤的供应商别名。

从您的描述中,似乎您正在计算每个供应商可以作为产品列出但没有列出的每个类别中的零件数量。 这基本上就是每个类别可以列出的零件数量与实际列出的零件数量之间的差异。 因此,您可以将可能的和左连接计数为实际的计数

基于sqlfiddle,下面的代码还假设您希望能够关注一个季节类型,并且只有partdata中列出的部件(带sales?)是相关的

   select c.name as category
      , v.name as vendor
      , cpartcount.parts
      , cpartcount.parts-coalesce(cvpartcount.parts,0) as missingparts
   from vendor v
   cross join
   ( 
     select pt.category_id, count(pt.id) as parts
     from part pt 
     where pt.id in 
     (
       select s.part_id
       from season s 
       where s.type='Type A'
     )
     and pt.id in 
     (
       select pd.part_id
       from part_data pd
     )
     group by pt.category_id
   ) cpartcount
   join category c
   on cpartcount.category_id=c.id
   left join
   ( 
      select pt.category_id, v.id as vendor_id, count(pt.id) as parts
      from part pt,vendor v
      where (v.id,pt.id) IN
      (
        select p.vendor_id, s.part_id
        from product p
        join inventory i
        on p.id=i.product_id
        join season s 
        on i.season_id = s.id
        join part_data pd
        on s.part_id=pd.part_id
        where s.type='Type A'   
      ) 
      group by pt.category_id,v.id
   ) as cvpartcount
   on cpartcount.category_id=cvpartcount.category_id
   and v.id=cvpartcount.vendor_id 
你能添加一个样本输出吗