【问题标题】:SQL selecting rows using FOREIGN KEYSSQL 使用 FOREIGN KEYS 选择行
【发布时间】:2016-03-30 16:24:35
【问题描述】:

suppliers表:

PK_ID  supplier  supplier_code
  1       x           abc
  2       y           def

items表:

PK_ID   item_name   
 1        Name1           
 2        Name2

items_suppliers 带有 外键的表

FK_ID_items  FK_ID_suppliers           
    1              1
    2              1  

我愿意

选择一个项目并从suppliers 表中查找具有相同供应商的其他项目。 然后它应该返回“Name2”项。

[编辑]

获取ITEM1 及其全部 suppliers 并在每个匹配的supplier 中查找下一个item 仅在之后 在每个@987654333 中查找下一个item @ 匹配。


正确的答案(感谢 @DarwinvonCorax - @ThorstenKettner 的宝贵帮助):

SELECT i2.item_name, s.supplier, s.supplier_code
FROM items i1
JOIN items_suppliers is1
ON i1.PK_ID = is1.FK_ID_items
JOIN items_suppliers is2
ON is1.FK_ID_suppliers = is2.FK_ID_suppliers
JOIN items i2
ON is2.FK_ID_items = i2.PK_ID
JOIN suppliers s
ON is1.FK_ID_suppliers = s.PK_ID
WHERE i1.item_name = 'Name1'
ORDER BY
CASE WHEN i2.item_name = 'Name1'
     THEN 1
     ELSE 2
  END,
i2.item_name, s.supplier;

@ThorstenKettner 提出的解决方案也是正确的

select item_name
 from items
where pk_id in
(
 select fk_id_items
   from items_suppliers
  where fk_id_suppliers in
  (
    select fk_id_suppliers  
    from items_suppliers
    where fk_id_items = 
      (
       select pk_id from items where item_name = 'Name1')
      )
 );

【问题讨论】:

  • 不要混合隐式和显式连接语法。始终对所有表使用joinwherejoin 之后出现
  • 我已经编辑了 SQL stmt,但它返回了所选 item 的供应商,这并不奇怪......

标签: mysql sql join foreign-keys relational-database


【解决方案1】:

您需要进行回文连接(我的术语)。首先找到指定项目的供应商 ID,然后从 items_suppliers 查找同一供应商 ID 的所有记录。你加入itemsitems_suppliersitems_suppliersitems。然后在末尾添加 suppliers 以获取供应商名称。

获得您想要的强制排序顺序有点棘手。我使用了我在其他地方看到的黑客,但老实说,我不知道它有多普遍。我执行SELECT 来获取Item1 的供应商,并在结果中添加一个值1 的常量列。我再做一次SELECT 以获取所有项目的供应商除了 Item1,并添加常量列2UNION 这两个查询并从该结果中仅选择您想要的列,但 ORDER BY 是常量,它将首先对值为 1Item1 的供应商)的所有行进行排序。

SELECT item_name, supplier, supplier_code
  FROM
    (SELECT '1' AS orderer, i1.item_name AS item_name, s.supplier AS supplier, s.supplier_code AS supplier_code
      FROM items i1
      JOIN items_suppliers is1
        ON i1.PK_ID = is1.FK_ID_items
      JOIN suppliers s
        ON is1.FK_ID_suppliers = s.PK_ID
      WHERE i1.item_name = 'Name1'
    UNION ALL
    SELECT '2', i2.item_name, s.supplier, s.supplier_code
      FROM items i1
      JOIN items_suppliers is1
        ON i1.PK_ID = is1.FK_ID_items
      JOIN items_suppliers is2
        ON is1.FK_ID_suppliers = is2.FK_ID_suppliers
      JOIN items i2
        ON is2.FK_ID_items = i2.PK_ID
      JOIN suppliers s
        ON is1.FK_ID_suppliers = s.PK_ID
      WHERE i1.item_name = 'Name1'
        AND i2.PK_ID <> i1.PK_ID
    ) r
  ORDER BY orderer, item_name, supplier;

不过,根据 Thorsten Kettner 的 cmets,我意识到我的 SQL 有点生疏和过时;他的建议看起来像这样:

SELECT i2.item_name, s.supplier, s.supplier_code
  FROM items i1
  JOIN items_suppliers is1
    ON i1.PK_ID = is1.FK_ID_items
  JOIN items_suppliers is2
    ON is1.FK_ID_suppliers = is2.FK_ID_suppliers
  JOIN items i2
    ON is2.FK_ID_items = i2.PK_ID
  JOIN suppliers s
    ON is1.FK_ID_suppliers = s.PK_ID
  WHERE i1.item_name = 'Name1'
  ORDER BY
    CASE WHEN i2.item_name = 'Name1'
         THEN 1
         ELSE 2
      END,
    i2.item_name, s.supplier;

【讨论】:

  • 它有效,但有很大的 BUT。如果 item = Name1 有更多 suppliers' 对 - 它为每个供应商对值返回其他项目名称,例如:Name1 和其他项目与供应商(PK_ID = 1)然后再次 Name1 和其他项目但与供应商(PK_ID=4)
  • 如果Name1 有多个供应商,查询将返回每个供应商的所有商品。这就是您提出的问题。
  • 但它以循环方式返回它:1. Take (Name1 and its FIRST supplier) -> 2. Show other NameX with take @987654345 @ 并仅显示 ONE supplier -> 3. 取 (Name2 及其现在 SECOND supplier) 等...
  • 我想要的:获取ITEM1 及其全部 suppliers 并在每个匹配的supplier 中找到下一个item 只有这样 找到下一个item 与每个匹配的supplier
  • 所以您想查看Item1 的所有供应商,然后查看Item2 的所有供应商等?如果那是正确的,我可以做到,但它会有点难看。
【解决方案2】:

一步一步做:

  1. 查找项目“Name1”的项目 ID。
  2. 查找该商品 ID 的所有供应商。
  3. 查找这些供应商的所有商品 ID。
  4. 找到找到的 ID 的项目名称。

查询:

select item_name
from items
where pk_id in
(
  select fk_id_items
  from items_suppliers
  where fk_id_suppliers in
  (
    select fk_id_suppliers  
    from items_suppliers
    where fk_id_items = (select pk_id from items where item_name = 'Name1')
  )
);

如果您想从列表中排除 and item_name &lt;&gt; 'Name1',您可以添加它。

【讨论】:

  • 它工作 BUT 然后再次:如果我选择 suppliersupplier_code 到您的 stmt 的第一行,它会在循环中返回结果 - 它考虑了一个 @987654325 @ 并正在寻找带有此 supplier 的其他项目,然后再次下一个 supplier 并再次寻找该供应商的其他项目...我相信有更简单的解决方案,也许使用 JOIN 所有结果都显示在一次 - 但感谢工作回复和分步指导,它会有所帮助
  • 我想要的:获取ITEM1 及其全部 suppliers 并在每个匹配的supplier 中找到下一个item 只有这样 找到下一个item 与每个匹配的supplier
  • 您使这听起来像一个递归,但这只是一个循序渐进的方法:获取项目,获取其供应商,获取他们的项目。你还会如何解决这个问题?查询是直截了当的,应该会产生一个好的执行计划。当然,您可以对某些连接执行相同的操作,但这并不那么简单。编辑:这是您第一条评论的答案。我现在正在读第二个...
  • 至于您的第二条评论:您似乎正在尝试找到访问表记录的最佳算法。但这不是你的工作,也不是 SQL 的工作方式。在 SQL 中,您只需告诉 DBMS what 来选择(并且为此使用最简单易读的查询),然后让 DBMS 找到最佳访问方法。它是为这项工作而生的,所以相信它会做好。
  • 我觉得可以用JOINs 来简化它:)接近完美。
猜你喜欢
  • 2012-12-29
  • 2016-10-16
  • 2013-07-01
  • 2014-08-08
  • 2014-04-08
  • 1970-01-01
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多