4

次の問題の結果を得るために、最速で複雑でない方法を見つけようとしています。

私は (たとえば) レゴ キットの DB を持っています。各キットには説明と、必要なレゴ ピースのリストとその数が含まれています。ユーザーは、自分のレゴ ピースのコレクションを挿入し、自分のピースでどのキットを構築できるか、他のピースを購入した場合に他に何が構築できるかを尋ねることができます (最初の制限は、1 種類のピースしか購入できないことです)。

私が持っているのはおおよそこれです:

LegoDesign
- id
- name

LegoBlock
- id
- type
- weight
- description

LegoBlockForDesign
- LegoDesign.id
- LegoBlock.id
- numberOfPiecesNeeded

Collection
(- User.id)
- LegoBlock.id
- quantityAvailable

たとえば、DB には StarWar の Death Star の LegoDesign が含まれています。LegoBlock には、「2x2 黒四角」や「小さな車輪」などのピースの長いリストが含まれています。LegoBlockForDesign は、LegoBlocks をデス スターの LegoDesign に割り当てます (たとえば、「2x2 黒四角」の 1000 個のピース​​)。Table コレクションには、ユーザーが持っているピースが含まれています。ここでの問題は、ユーザーが持っているピースでデザインを照会する必要があることです。これは、最初に LegoBlock.id をチェックし、次に numberOfPiecesNeeded をチェックすることを意味します。星。これが最初のクエリです。2 つ目は、私が持っているブロックとコレクションにないブロックを含むデザインをチェックする必要があります。これは、所有しているが適切な量よりも少ないレゴブロックと、所有していないブロックを含むデザインを確認する必要があることを意味します。後者には、手動で設定できる制限が必要です。購入するピースの数の制限 (つまり、最大 30 ピース) またはピースの難易度の制限 (つまり、購入する「特別なブロック」がない、特別なホイールやキャラクターのみが存在するなど) の間でユーザーが選択できるようにすることを考えていました。特定のデザイン (スターウォーズのキャラクターなど)。

特に、ブロックの存在だけでなく数量もチェックする必要があるため、SQL で実行できるかどうかは完全にはわかりません。

編集: LegoBlock.type と LegoBlock.weight を追加しました。このようにして、type = common,rare,unique を定義して、通常のピースまたは特定のピース (レアと定義できるスター ウォーズのキャラクターなど) を定義できます。デザイン)。代わりに重量を使用して優先順位を付けることができます (私は青が好きなので、青のピースを購入しなければならないデザインを見たいと思います)。

4

3 に答える 3

3

このクエリを試してください...これにより、ユーザーがすべてのブロックとブロックの数量を持っている LegoDesigns が得られます。

SELECT
    c.id, c.name
FROM
    Collection a
INNER JOIN
    LegoBlockForDesign b ON 
        a.LegoBlock.id = b.LegoBlock.id AND
        a.quantityAvailable >= b.numberOfPiecesNeeded
INNER JOIN
    LegoDesign c ON b.LegoDesign.id = c.id
INNER JOIN
    (
        SELECT LegoDesign.id, COUNT(1) AS totalneeded
        FROM LegoBlockForDesign
        GROUP BY LegoDesign.id
    ) d ON c.id = d.LegoDesign.id
WHERE
    a.User.id = <userid here>
GROUP BY
    c.id, c.name, d.totalneeded
HAVING 
    COUNT(1) = d.totalneeded

編集 2:このクエリは、現在のコレクションに加えて、購入しようとしているユーザーが選択した追加のレゴ ブロックを指定して、ユーザーが構築できるすべてのデザインを取得します。

SELECT 
    a.id, a.name
FROM
    (
        SELECT
            c.id, c.name, NULL AS notInCollection
        FROM
            Collection a
        INNER JOIN
            LegoBlockForDesign b ON a.LegoBlock.id = b.LegoBlock.id
        INNER JOIN
            LegoDesign c ON b.LegoDesign.id = c.id
        WHERE
            a.quantityAvailable >= b.numberOfPiecesNeeded AND
            a.User.id = <userid here>
        UNION ALL
        SELECT
            d.id, d.name, 1 AS notInCollection
        FROM
            LegoDesign d
        INNER JOIN
            LegoBlockForDesign e ON d.id = e.LegoDesign.id
        WHERE
            e.LegoBlock.id IN (<comma sepd list of legoblockids here>)
    ) a
INNER JOIN
    (
        SELECT LegoDesign.id, COUNT(1) AS totalneeded
        FROM LegoBlockForDesign
        GROUP BY LegoDesign.id
    ) b ON a.id = b.LegoDesign.id
GROUP BY 
    a.id, a.name, b.totalneeded
HAVING 
    COUNT(1) = b.totalneeded AND 
    COUNT(a.notInCollection) > 0

基本的に、UNION ALLこれらの特定の選択されたブロックを含むデザインを表す行にタックを付けHAVING COUNT(*)て、外側でそれらを考慮に入れることができるようにします。FROM サブセレクトのnotInCollectionフィールドは、パーツがすでにユーザーのコレクションにあるかどうかを示すフラグです。そのため、ユーザーがコレクションHAVING COUNT(f.notInCollection) > 0にすべてのパーツを既に持っているデザインは除外されます。これは、あなたが実行できる a を実行するよりもはるかに効率的NOT IN (<1st query as subquery>)です。

クエリは、ユーザーが以前に提示されており、まだ持っていないレゴブロックのリストからのみ選択できることを前提としています。そうしないと、UNION に重複があり、結果が失われます。

ユーザーが複数のレゴブロックを選択して、より多くのブロックを選択するにつれて構築できるデザインの数が増えることを確認できるように、レゴブロック ID のリストを入れることもできます。

于 2012-06-11T10:02:44.567 に答える
2

最初のクエリ。 これにより、ブロック名と、必要なピースとユーザーが LegoBlock タイプで持っているピースとの差が得られます (ユーザーが十分または必要以上に持っている場合は 0)。

すべての詳細が必要ない場合は、これをサブクエリとして使用できます

select lbd.legoBlock_id, lb.Description, Greatest(lbd.NumberOfPiecesNeeded - Coalesce(c.quantityAvailable, 0), 0)
from legoBlockForDesign lbd
inner join LegoBlock lb on lb.Id = lbd.LegoBlock_id

left join Collection c on c.legoBlock_id = lbd.legoBlock_id
where lbd.LegoDesign_id = <the design id queried>
and c.User_Id = <the user id queried>
-- if you want only the blocks with missing quantity
--and Greatest(lbd.NumberOfPiecesNeeded - Coalesce(c.quantityAvailable, 0), 0) > 0

2 番目のクエリは、どのフィルターを使用するかわからないため、答えるのが困難です (「特別なブロック」はモデルに表示されません。LegoBlock テーブルにあると思われます。確認してください)。また、「欠けている個数」とは何ですか?グローバルですか ( 30 = 15 2*2 + 10 3*1 + 5 125*3) ?

さて、数量フィルターを使用すると、そのようなことができます

2 番目のクエリ

select ld.Id, ld.Description, Sum(Greatest(lbd.NumberOfPiecesNeeded - Coalesce(c.quantityAvailable, 0), 0)) missingPieces
from legoDesign ld
inner join LegoBlockDesign lbd on lbd.LegoDesign_Id = ld.Id
inner join LegoBlock lb on lb.Id = lbd.LegoBlock_id
left join Collection c on c.legoBlock_id = lbd.legoBlock_id
where c.User_Id = <the user id queried>
group by ld.Id, ld.Description
--Filter on quantity
-- having Sum(Greatest(lbd.NumberOfPiecesNeeded - Coalesce(c.quantityAvailable, 0), 0))<=30
--ORDER BY the "less missing pieces"
--ORDER BY Sum(Greatest(lbd.NumberOfPiecesNeeded - Coalesce(c.quantityAvailable, 0)
于 2012-06-11T09:33:24.117 に答える
0

最初のクエリ-デザインを調べて、そのデザインで使用されているブロックのブロックが0個以上残っていることを確認することで、ユーザーがコレクションから作成できるデザインを取得できます。

  select design 
  from    (select lb.*, ld.id ,lbfd.numberOfPiecesNeeded numberOfPiecesNeeded,
                  ld.name design 
           from LegoDesign ld, LegoBlock lb ,LegoBlockForDesign lbfd 
           where ld.id=lbfd.id 
           and lb.id=lbfd.lbid ) a 
  left outer join Collection coll
        on coll.legoblock_id = a.legoblock_id 
        and coll.user_id=`<USER_ID> `
  group by a.legodesign_id 
  having min(coalesce(coll.quantityAvailable,0)-a.numberOfPiecesNeeded)>=0;

2番目のクエリでは、havingこのように句を変更するsum(a.numberOfPiecesNeeded-coalesce(coll.quantityAvailable,0)) between 1 and xと、設計を完了するために必要な最大ピース数がxにならない設計が得られます。このデータを同じクエリでLegoBlockForDesignおよびLegoblockと結合して、個々のブロック数を取得できます。

于 2012-06-11T17:07:54.647 に答える