web-dev-qa-db-ja.com

複数のサブクエリでの複雑な結合

いつも皆さんを悩ませ続けて申し訳ありませんが、SQLはまだ私にとって新しいものです。 Store_location、Product、Sizes、Sells、Available_in、Offers、Currencyのテーブルがあります。目標は、販売された製品のみを返す複数のサブクエリ([〜#〜] [〜#〜]句が必要)で1つのクエリを実行できるようにすることですすべての店舗の場所で、他には何もありません。また、スケーラブルである必要があり、店舗が開いたり閉じたりした場合でも、コードを変更する必要はありません。私は始めるためにこれらのとりとめのない問題を抱えていますが、そこからどこへ行くべきかわかりません。以下の最初の選択ステートメントは、クエリが成功したときに表示する必要があるものです。 SELECT Store_location.store_name、Product.product_name、Sizes.size_option、COUNT(store_location.store_id)AS store_count

JOIN Sells ON Sells.store_location_id = Store_location.store_location_id
JOIN Product ON Product.product_id = Sells.product_id


JOIN ON Available_in.product_id = Product.product_id
JOIN ON Available_in.sizes_id = Sizes.sizes_id

結合を実行して、使用する必要のあるテーブルに外部キー制約がある場所を表示しようとしました。追加情報が必要な場合は、ご提供いたします。関連するすべてのテーブルの内容を表示する link を追加しました。 WHEREステートメントに少なくとも1つのサブクエリを埋め込む必要があることはわかっていますが、そこに何を入れるかわかりません。たくさんの情報をお伝えすることは承知しており、誰にも手伝う時間がない場合は理解しますが、ガイダンスはありがたいです。

私はそれが遅いリクエストであることを理解していますが、誰かが[〜#〜]存在する[〜#〜]を使用する方法で私を助けることができれば、私は非常に感謝します。

2
user121168

全店で販売されている商品を探すのが一番難しいようです。ほとんどの場合と同様に、これを行う方法は複数ありますが、次のクエリは、すべての店舗で販売されているすべての製品IDを返します。

SELECT product_id
  FROM Product
EXCEPT -- exclude product IDs that are not sold in all stores
SELECT product_id
  FROM (-- Generate list of product IDs and the stores that do NOT sell them
        -- select all possible products and stores ...
        SELECT product_id, store_id
          FROM Product CROSS JOIN Store_location
        EXCEPT -- ... for the products actually sold by each store
        SELECT product_id, store_id
          FROM Sells
       ) Not_At_All_Stores

サブクエリは、可能なすべての商品と店舗のリストを取得し、対象の店舗で実際に販売された商品を表すコンボを削除します。これは、指定された店舗で販売されていない製品のみを残します。

次に、製品の完全なリストを取得し、少なくとも1つのストアで販売されていない(現在)とわかっている製品をすべて削除します。それはすべての店で販売された製品を残すだけです。

ここからは、すべてを結合するだけです。次のようなFROM句で終了します。

SELECT Store_location.store_name
      ,Product.product_name
      ,Sizes.size_option
  FROM (
        SELECT product_id
          FROM Product
        EXCEPT -- exclude product IDs that are not sold in all stores
        SELECT product_id
          FROM (-- Generate list of product IDs and the stores that do NOT sell them
                -- select all possible products and stores ...
                SELECT product_id, store_id
                  FROM Product CROSS JOIN Store_location
                EXCEPT -- ... for the products actually sold by each store
                SELECT product_id, store_id
                  FROM Sells
               ) Not_At_All_Stores
       ) uprod -- for a Universally sold PRODuct
         INNER JOIN Product ON (uprod.product_id = Product.product_id)
         INNER JOIN Available_in ON (uprod.product_id = Available_in.product_id
           INNER JOIN Sizes ON (Available_in.size_id = Sizes.size_id)
         INNER JOIN Sells ON (uprod.product_id = Sells.product_id)
           INNER JOIN Store_location ON (Sells.store_id = Store_location.store_id)
 ORDER BY store_name, product_name, size_option

WHERE句は必要ありません(要求した内容に基づく)。店舗情報は冗長であることに注意してください。これらの製品はすべての店舗で販売されているため、5つの店舗名のいずれかが各コピーの前に付加された、同じ基本結果の5つのコピーを取得しているだけです。店舗名は、すべての店舗でされていないが販売されている製品の方がはるかに興味深いものです。

注:Productテーブルのインデックス付け方法に応じて、product_name列をNot_At_All_Storesサブクエリに追加し、そこから引き継ぐことができます。ただし、これは、すべての可能な製品およびストアのリストにそれを含める必要があることを意味します。これにより、EXCEPT操作を実行するときに、より多くのメモリが消費されます。

更新:最新のコメントから明らかなように、この割り当てでは、WHERE句、WHERE句のサブクエリ、およびEXISTSを使用する必要があります。ここからそこに行くには:

  • クエリからuprodを削除します。 uprod.product_idにリンクされているものはすべてProduct.product_idにリンクする必要があります。
  • 最初のクエリをサブクエリとして使用できます。
  • サブクエリにproduct_idが存在するレコードが必要です。

これはisの宿題なので、少なくとも実際に組み立ててみましょう。

私の回答の最初のクエリをサブクエリとして使用し、製品を探します

5
RDFozz

これは、HAVING句を使用して解決できます。

with cte as(
Select
    p.product_id
    ,p.product_name
from
    Product p
    inner join
        sells s on
        s.product_id = p.product_id
group by
    p.product_id
    ,p.product_name
having count(p.product_id) = (select count(distinct store_location_id) from sells))

select
    c.product_id
    ,c.product_name
    ,s.store_location_id
    ,a.sizes_id
from
    cte c
    inner join
        sells s on
        s.product_id = c.product_id
    inner join
        Avaliable_in a on
        a.product_id = c.product_id
1
scsimon