SQL查询让孩子拥有相同数量的玩具

时间:2015-03-23 03:30:59

标签: sql sql-server algorithm

试图找出用于平衡儿童玩具的SQL查询。

Children表中,列为:

ID INT, <br>
FNAME NCHAR(50), <br>
LNAME NCHAR(50), <br>
NumberofToys INT

然后在Toys表中我们有:

ID INT, <BR>
ToyName NCHAR(50) <BR>
ChildrenID INT -->This is a FK to the Children table

所以这里的关系是一对多(一个孩子可以有0到多个玩具)。

平衡孩子们的玩具意味着以下几点:

  1. 如果有少量儿童和数量的玩具,那么每个儿童应该有(m / n)玩具

  2. 如果有少量儿童和n + 1个玩具,那么每个儿童将拥有(m / n)玩具,其中一个孩子在桌子上有n + 1个玩具。

  3. 如果有少量儿童和n-1个玩具,那么每个儿童将拥有(m / n)玩具,其中一个孩子在桌子上有n-1个玩具。

  4. 如果已经平衡并且要从桌子上移走一个孩子,那么他们的玩具应该一次分配一个,直到他们的玩具份额完全分配。

  5. 如果已经平衡且其中一个儿童玩具已从玩具桌上移除,那么表中剩余的玩具应均匀重新分配

  6. 样品组(预平衡):

    Children
    ID    FNAME    LNAME    NumberofToys  
    
    1      Bob      Jones     3
    2      Jenny    James     5
    
    
    Toys
    ID    ToyName    ChildrenID
    1      Bear       1
    2      Train      2
    3      Truck      2
    4      Car        2
    

    解决方案集:

    Children
    ID    FNAME    LNAME    NumberofToys  
    
    1      Bob      Jones      2
    2      Jenny     James     2
    
    
    Toys
    ID    ToyName    ChildrenID
    1      Bear       1
    2      Train      1
    3      Truck      2
    4      Car        2
    

    我似乎无法在此获得正确的算法。将玩具添加到Toys表后,FK应该是第一个玩具数量最少的子ID。我尝试过的是:

    DECLARE @ToyCount INT,
    @ID INT
    --This should take care of the balancing problem.
    --Since Toys get added one at a time, just add to first Child
    ----with minimum amount of customers
    SET @ToyCount = (SELECT MIN(NumberofToys) FROM Children)
    
    --Store top id that has least amount of toys
        SET @ID = (SELECT TOP 1 ID
        FROM Children
        WHERE @ToyCount=NumberofToys)
    --This part is if a Child needs to be added to the table, NumberofToys would be originally 0
        INSERT INTO Children (FNAME, LNAME, NumberofToys)
        VALUES(@fname, @lname, 0);
    
    
    --Increasing the number of toys for the ID we SET above
    UPDATE Children
    SET NumberofToys = NumberofToys + 1
    WHERE ID=@ID
    

    如果用户手动“平衡”孩子们玩具的数量,则需要进行平衡。上面添加的部分修复了任何新玩具,但不包括预先存在的玩具。有人可以帮帮我吗?我对预先存在的玩具的尝试如下:

    DECLARE @ToyCount INT, @ToyCountMAX,
    @ID INT, @IDMAX INT, @IDTarget INT
    
    SET @ToyCount = (SELECT MIN(NumberofToys) FROM Children)
    SET @ToyCountMAX = (SELECT MAX(NumberofToys) FROM Children)
    
    
    --Store top id that has least amount of toys
        SET @ID = (SELECT TOP 1 ID
        FROM Children
        WHERE @ToyCount=NumberofToys)
    --Store top id that has most amount of toys
    SET @IDMAX = (SELECT TOP 1 ID FROM Children WHERE @ToyCountMAX=NumberofToys)
    
    --Take top id that has most amount of toys and set it to an ID that has least amount (I believe my problem is here. Can't get the syntax to set the top ChildrenID to the SELECT...on the right side of the = sign
    UPDATE Toys
    SET ChildrenID = (SELECT TOP 1 ChildrenID FROM Children WHERE NumberofToys=MIN(NumberofToys)
    WHERE ChildrenID=@IDMAX
        --Increasing the number of toys for the ID we SET above
        UPDATE Children
        SET NumberofToys = NumberofToys + 1
        WHERE ID=@ID
    
    --decreasing number of toys for the max ID
    UPDATE Children
    SET NumberofToys = NumberofToys - 1
    WHERE ID=@IDMAX
    

1 个答案:

答案 0 :(得分:1)

尝试以下商店流程,它应在任何阶段Toys之间平衡Children

注意:Children表中删除子项时,您需要维护外键关系。因此,

  1. 将孩子的玩具分配给表中的任何其他孩子
  2. 然后从表Children
  3. 中删除该子项
  4. 调用商店程序以重新平衡
  5. 存储过程

    CREATE PROCEDURE BalanceToys
    AS
    BEGIN
    
        -- While there is imbalance between children
        -- i.e. MAX toys owned minus MIN toys owned is greater than 1
        WHILE((SELECT MAX(cnt)-MIN(cnt) FROM (
            SELECT c.ID, SUM(CASE WHEN t.ID IS NOT NULL THEN 1 ELSE 0 END) Cnt
            FROM Children c
                LEFT JOIN Toys t ON c.ID = t.ChildrenID
            GROUP BY c.ID) v) > 1)
        BEGIN
    
            -- We rebalance 1 toy at a time
            -- the child with most toys will give 1 toy to the child with least toys
            UPDATE TOP (1) Toys
            SET ChildrenID = (SELECT TOP 1 c.ID
                FROM Children c
                    LEFT JOIN Toys t ON c.ID = t.ChildrenID
                GROUP BY c.ID
                ORDER BY SUM(CASE WHEN t.ID IS NOT NULL THEN 1 ELSE 0 END))
            WHERE ChildrenID = (SELECT TOP 1 c.ID
                FROM Children c
                    LEFT JOIN Toys t ON c.ID = t.ChildrenID
                GROUP BY c.ID
                ORDER BY SUM(CASE WHEN t.ID IS NOT NULL THEN 1 ELSE 0 END) DESC)
    
           -- Loop until all balanced
        END
    
        -- Update NumberofToys 
        UPDATE Children
        SET NumberofToys = (SELECT COUNT(*) FROM Toys WHERE ChildrenID = Children.ID)
    
    END
    GO