4

我正在尝试找到最快/不太复杂的方法来获得以下问题的结果。

我有一个(例如)乐高套件的数据库,其中每个套件都有一个描述和所需的乐高部件列表以及它们的数量。用户可以插入他的乐高积木集合,然后询问他可以用他的积木构建什么套件,如果他购买其他积木,他还可以积木什么(也许第一个限制是他只能购买一种类型的积木)。

我所拥有的大致是这样的:

LegoDesign
- id
- name

LegoBlock
- id
- type
- weight
- description

LegoBlockForDesign
- LegoDesign.id
- LegoBlock.id
- numberOfPiecesNeeded

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

例如,数据库包含用于 StarWar 的死星的 LegoDesign。LegoBlock 包含一长串“2x2 黑色方块”或“小轮子”等。LegoBlockForDesign 将 LegoBlocks 分配给死星的 LegoDesign(例如 1000 个“2x2 黑色方块”)。Table 集合包含用户拥有的部分。现在这里的问题是我必须使用用户拥有的部件查询设计,这意味着首先检查 LegoBlock.id 然后检查 numberOfPiecesNeeded 因为我可以有一些 2x2 黑色方块但不足以构建死亡星星。这是第一个查询。第二个应该检查包含我拥有的块以及我的收藏中没有的一些块的设计。这意味着我应该检查我拥有但数量少于正确数量的乐高积木,以及没有我拥有的积木的设计。后者需要一个可以手动设置的限制。我正在考虑让用户在购买件数的限制(即最多 30 件)或件件的难度限制(即没有“特殊块”可购买,例如仅存在一些特殊的轮子或角色)之间进行选择在特定的设计中(例如星球大战的角色)。

我不完全确定它可以在 SQL 中完成,特别是因为我必须检查数量而不仅仅是块的存在。

编辑:我添加了 LegoBlock.type 和 LegoBlock.weight。这样我可以定义 type = common,rare,unique 来定义普通或特定的部分(比如可以定义为稀有的星球大战角色。我不想购买这些作品,因为它们只能用于星球大战'设计)。重量可以用来优先考虑(我喜欢蓝色,所以我更愿意看到我必须购买蓝色件的设计)。

4

3 回答 3

3

试试这个查询......这将为您提供乐高设计,其中用户拥有所有积木和积木数量:

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(*)外部可以考虑它们。notInCollectionFROM 子选择中的字段是一个标志,指示该部件是否已经在用户的收藏中......因此HAVING COUNT(f.notInCollection) > 0不包括用户已经在他/她的收藏中拥有所有部件的设计。NOT IN (<1st query as subquery>)这比做你也可以做的要高效得多。

该查询假定用户先前已呈现并且只能从他/她还没有的乐高块列表中进行选择,否则 UNION 中将出现重复,这将导致结果丢失。

您还可以输入一个乐高积木列表,以便用户可以选择多个乐高积木,以查看随着他们选择更多积木而可以构建的设计数量不断增加。

于 2012-06-11T10:02:44.567 回答
2

第一个查询。 这将为您提供积木名称,以及所需部件与用户拥有的积木块类型之间的差异(如果用户有足够或超过需要,则为 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

第二个查询很难回答,因为我不知道您要使用哪些过滤器(“特殊块”没有出现在模型中,我假设它在 LegoBlock 表中,只需确认)。“丢失的件数”是什么意思?它是全局的(30 = 15 2*2 + 10 3*1 + 5 125*3)吗?

好吧,使用数量过滤器,您可以执行类似的操作

第二次查询

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;

对于第二个查询,having像这样更改子句sum(a.numberOfPiecesNeeded-coalesce(coll.quantityAvailable,0)) between 1 and x将给出设计,其中我们在完成设计所需的最大件数为 x 。我们可以将这些数据与 LegoBlockForDesign 和 Legoblock 在同一查询中加入,以获得每个单独的块数

于 2012-06-11T17:07:54.647 回答