根据不同的规则返回存储过程的值

时间:2013-05-04 08:20:26

标签: sql sql-server-2008 tsql

我正在编写一个存储过程来获取基于下表的值。

enter image description here

我根据买家的国籍填写公寓单位。

存储过程必须根据以下规则返回下一个非占用单位:

  • 如果有新的条目,我需要建议与新人相同国籍的被占用单位旁边的非占用单位

  • 如果上述条件未找到匹配项,则在未占用单位的楼层内分配第一个单位

  • 如果上述情况未找到匹配项,则分配一个两侧至少有两个空单位的单位

  • 如果上述条件未找到匹配项,则根据排序顺序分配第一个为空的展位

注意:

  • 每个单位都由Floor& amp;单否

  • 搜索时对于平面和地板的排序顺序应为1到n

示例输入:NAME:RANDY NATIONALITY:BRAZIL

SAMPLE OUTPUT :FLOOR:1 FLAT NO:4(w.r.t.到附图)

1 个答案:

答案 0 :(得分:1)

关键是为每个条件创建列,例如,如果下一个房屋所有者具有相同的国籍,则为一列;如果楼层为空,则为一列。

然后,您可以采用所有标准,并将其放置在ROW_NUMBER()函数的订单中,以按照您定义的顺序获取单位。以下查询中的关键部分是:

RowNumber = ROW_NUMBER() OVER(ORDER BY PrevIsNationalityMatch DESC, 
                                        NextIsNationalityMatch DESC, 
                                        EmptyFloor DESC, 
                                        EmptyFlatsEitherSide DESC,
                                        Floor, 
                                        FlatNo)

四列(PrevIsNationalityMatchNextIsNationalityMatchEmptyFloor', 'EmptyFlatsEitherSide)都是位字段,因此,如果存在前一个单位由同一国籍的人拥有的行,则总是被ROW_NUMBER函数排名第一,否则它会查找下一个单位是否由同一国籍的人拥有(我添加了这条规则似乎合乎逻辑,但可以通过将其从订单中删除而轻松删除),以及依此类推,直到它只是按地板和平面排序。

DECLARE @NewOwnerNationality VARCHAR(20) = 'BRAZIL';
WITH FlatOwnerNationality AS
(   SELECT  FlatMaster.Floor, 
            FlatMaster.FlatNo, 
            FlatMaster.IsOccupied,
            IsNationalityMatch = CASE WHEN OwnerMaster.OwnerNationality = @NewOwnerNationality THEN 1 ELSE 0 END
    FROM    FlatMaster
            LEFT JOIN OwnerMaster
                ON OwnerMaster.OwnerName = FlatMaster.OwnerName
), Flats AS
(   SELECT  FlatMaster.Floor,
            FlatMaster.FlatNo,
            FlatMaster.IsOccupied,
            EmptyFlatsEitherSide = CASE WHEN PrevFlat.IsOccupied = 'NO' AND NextFlat.IsOccupied  = 'NO' THEN 1 ELSE 0 END,
            EmptyFloor = CASE WHEN COUNT(CASE WHEN FlatMaster.IsOccupied = 'YES' THEN 1 END) OVER(PARTITION BY FlatMaster.Floor) = 0 THEN 1 ELSE 0 END,
            PrevIsNationalityMatch = ISNULL(PrevFlat.IsNationalityMatch, 0),
            NextIsNationalityMatch = ISNULL(NextFlat.IsNationalityMatch, 0)
    FROM    FlatMaster
            LEFT JOIN FlatOwnerNationality PrevFlat
                ON PrevFlat.Floor = FlatMaster.Floor
                AND PrevFlat.FlatNo = FlatMaster.FlatNo - 1
            LEFT JOIN FlatOwnerNationality NextFlat
                ON NextFlat.Floor = FlatMaster.Floor
                AND NextFlat.FlatNo = FlatMaster.FlatNo + 1
), RankedFlats AS
(   SELECT  *,
            RowNumber = ROW_NUMBER() OVER(ORDER BY PrevIsNationalityMatch DESC, 
                                                    NextIsNationalityMatch DESC, 
                                                    EmptyFloor DESC, 
                                                    EmptyFlatsEitherSide DESC,
                                                    Floor, 
                                                    FlatNo)
    FROM    Flats
    WHERE   IsOccupied = 'NO'
)
SELECT  Floor,
        FlatNo,
        MatchedOn = CASE WHEN PrevIsNationalityMatch = 1 THEN 'First Flat after same nationality owner'
                        WHEN NextIsNationalityMatch = 1 THEN 'First Flat before same nationality owner'
                        WHEN EmptyFloor = 1 THEN 'No Nationality Match, placed on empty floor'
                        WHEN EmptyFlatsEitherSide = 1 THEN 'Next flat with empty flats either side'
                        ELSE 'First Available Flat'
                    END
FROM    RankedFlats
WHERE   RowNumber = 1;

<强> Brazil Example - Floor 1, Flat 4

<强> England Example - Floor 1, Flat 2

<强> Spain Example - Floor 2, Flat 1

修改

DECLARE @NewOwnerNationality VARCHAR(20) = 'BRAZIL';

WITH FlatOwnerNationality AS
(   SELECT  FlatMaster.Floor, 
            FlatMaster.FlatNo, 
            FlatMaster.IsOccupied,
            IsNationalityMatch = CASE WHEN OwnerMaster.OwnerNationality = @NewOwnerNationality THEN 1 ELSE 0 END
    FROM    FlatMaster
            LEFT JOIN OwnerMaster
                ON OwnerMaster.OwnerName = FlatMaster.OwnerName
), Flats AS
(   SELECT  FlatMaster.Floor,
            FlatMaster.FlatNo,
            FlatMaster.IsOccupied,
            EmptyFlatsEitherSide = CASE WHEN PrevFlat.IsOccupied = 'NO' AND NextFlat.IsOccupied  = 'NO' AND PrevFlat2.IsOccupied = 'NO' AND NextFlat2.IsOccupied  = 'NO' THEN 1 ELSE 0 END,
            EmptyFloor = CASE WHEN COUNT(CASE WHEN FlatMaster.IsOccupied = 'YES' THEN 1 END) OVER(PARTITION BY FlatMaster.Floor) = 0 THEN 1 ELSE 0 END,
            PrevIsNationalityMatch = ISNULL(PrevFlat.IsNationalityMatch, 0),
            NextIsNationalityMatch = ISNULL(NextFlat.IsNationalityMatch, 0)
    FROM    FlatMaster
            LEFT JOIN FlatOwnerNationality PrevFlat
                ON PrevFlat.Floor = FlatMaster.Floor
                AND PrevFlat.FlatNo = FlatMaster.FlatNo - 1
            LEFT JOIN FlatOwnerNationality NextFlat
                ON NextFlat.Floor = FlatMaster.Floor
                AND NextFlat.FlatNo = FlatMaster.FlatNo + 1
            LEFT JOIN FlatMaster PrevFlat2
                ON PrevFlat2.Floor = FlatMaster.Floor
                AND PrevFlat2.FlatNo = FlatMaster.FlatNo - 2
            LEFT JOIN FlatMaster NextFlat2
                ON NextFlat2.Floor = FlatMaster.Floor
                AND NextFlat2.FlatNo = FlatMaster.FlatNo + 2

), RankedFlats AS
(   SELECT  *,
            RowNumber = ROW_NUMBER() OVER(ORDER BY PrevIsNationalityMatch DESC, 
                                                    NextIsNationalityMatch DESC, 
                                                    EmptyFloor DESC, 
                                                    EmptyFlatsEitherSide DESC,
                                                    Floor, 
                                                    FlatNo)
    FROM    Flats
    WHERE   IsOccupied = 'NO'
)
SELECT  Floor,
        FlatNo,
        MatchedOn = CASE WHEN PrevIsNationalityMatch = 1 THEN 'First Flat after same nationality owner'
                        WHEN NextIsNationalityMatch = 1 THEN 'First Flat before same nationality owner'
                        WHEN EmptyFloor = 1 THEN 'No Nationality Match, placed on empty floor'
                        WHEN EmptyFlatsEitherSide = 1 THEN 'Next flat with empty flats either side'
                        ELSE 'First Available Flat'
                    END
FROM    RankedFlats
WHERE   RowNumber = 1;