2013-03-10 115 views
3

我不知道这是我在一个很长的一天的后端,或者我已经得到了编码器等效的编写器块,但我想不出一个干净的方式做到这一点。Tricky where子句

我有一个存储网页菜单结构的表,我想要一个简单的存储过程,它将根据Web应用程序中的会话参数返回相关的菜单项。

采取以下的(简化的)例子:

--#### Create example table 
CREATE TABLE [dbo].[tbl_Page](
    [PageID] [int] IDENTITY(1,1) NOT NULL, 
    [RequireLogin] [bit] NOT NULL, 
    [RequireAdmin] [bit] NOT NULL, 
    [HideIfLoggedIn] [bit] NOT NULL 
) 
GO 

--#### Insert Dummy Data 
SET IDENTITY_INSERT [dbo].[tbl_Page] ON 
INSERT [dbo].[tbl_Page] ([PageID], [RequireLogin], [RequireAdmin], [HideIfLoggedIn]) VALUES (2, 1, 0, 0) 
INSERT [dbo].[tbl_Page] ([PageID], [RequireLogin], [RequireAdmin], [HideIfLoggedIn]) VALUES (3, 1, 1, 0) 
INSERT [dbo].[tbl_Page] ([PageID], [RequireLogin], [RequireAdmin], [HideIfLoggedIn]) VALUES (4, 0, 0, 1) 
INSERT [dbo].[tbl_Page] ([PageID], [RequireLogin], [RequireAdmin], [HideIfLoggedIn]) VALUES (5, 0, 0, 0) 
SET IDENTITY_INSERT [dbo].[tbl_Page] OFF 

--#### Create menu procedure 
CREATE PROCEDURE usp_GetSubMenu 
    @ParentID INT , 
    @IsLoggedIn BIT , 
    @IsAdmin BIT 
AS 
    BEGIN 
     SET NOCOUNT ON; 

     SELECT PageID , 
       RequireLogin , 
       RequireAdmin , 
       HideIfLoggedIn 
     FROM tbl_Page 
     WHERE ???????????? 
    END 
GO 

对于给定的数据。例如,下面的需求是真实的:

  1. 页ID 2应该只列出如果@IsLoggedIn = 1
  2. 页面ID 3只应列出如果@IsLoggedIn = 1@IsAdmin = 1
  3. 页面ID 4应该一直列出除非@IsLoggedIn = 1(有可能是需要登录用户(甚至管理员用户)但仍然需要隐藏的页面 - 这是我的大脑爆炸的位... )
  4. 页ID 5应该是可见的所有的时间,无论用户是否登录或没有,如果他们是管理员或不是因为它不要求用户名和它不是隐藏登录用户
+0

你可以给样品记录以表格的形式? – 2013-03-10 22:10:39

+2

我个人更喜欢你给它的格式。使得设置一个SQL小提琴更容易。 – 2013-03-10 22:20:58

+0

关于#3,如果页面同时设置了RequireLogin和HideIfLoggedIn,这是否意味着它应该被排除在外,而不管@ IsLoggedIn的值?或者一种偏好优先于另一种? – 2013-03-11 00:01:40

回答

2
select PageID, 
    RequireLogin, 
    RequireAdmin, 
    HideIfLoggedIn 
from tbl_Page 
where (HideIfLoggedIn <> @IsLoggedIn) 
    and (RequireLogin = 0 or @IsLoggedIn = 1) 
    and (RequireAdmin = 0 or @IsAdmin = 1) 

适合我。评论后

编辑:

select PageID, 
    RequireLogin, 
    RequireAdmin, 
    HideIfLoggedIn 
from tbl_Page 
where ((HideIfLoggedIn <> @IsLoggedIn) 
    and (RequireLogin = 0 or @IsLoggedIn = 1) 
    and (RequireAdmin = 0 or @IsAdmin = 1)) 
    or (RequireLogin = 0 and RequireAdmin = 0 and HideIfLoggedIn = 0) 

我已经更新查询,以赶上你的最后一个要求,并更新了以下SQL小提琴:

SQL Fiddle@IsLoggedIn = 1, IsAdmin = 0 - PageID2,5显示。

SQL Fiddle for @IsLoggedIn = 1, IsAdmin = 1 - PageID2,3,5显示。

SQL Fiddle for @IsLoggedIn = 0, IsAdmin = 1 - PageID4,5显示。

+0

非常接近 - 做得很好,但是我忘记了我的示例中最常见的情况,当RequireLogin = 0且RequireAdmin = 0且HideIfLoggedIn = 0时,这表示任何人都应该看到 - 登录或不需要的东西,我需要调整答案也要考虑到这一点。 - 我修订我的问题,包括这个场景(页ID 5) - 编号有兴趣看看你会如何解决这个:) – HeavenCore 2013-03-10 23:25:56

+0

OK,更新;由于这种新的情况并没有真正匹配其余的逻辑(尤其是* @ IsLoggedIn *),我认为最简单的做法是在最后添加一个最后一个检查来捕获特定的组合。所有更新的示例现在都可以使用让我知道事情的后续。 – 2013-03-10 23:59:32

1
SELECT PageID , 
      RequireLogin , 
      RequireAdmin , 
      HideIfLoggedIn 
    FROM tbl_Page 
    WHERE 
    (@IsLoggedIn = 1 AND [HideIfLoggedIn] = 0) 
    AND [RequireLogin] = @IsLoggedIn 
    AND [RequireAdmin] = @IsAdmin   
1

我认为这有更好的可读性当where子句围绕负结构...

SELECT 
    PageID, 
    RequireLogin, 
    RequireAdmin, 
    HideIfLoggedIn 
FROM 
    tbl_Page 
WHERE 
    NOT 
    (
     (HideIfLoggedIn = 1 AND @IsLoggedIn = 1) 
     OR (RequireLogin = 1 AND @IsLoggedIn = 0) 
     OR (RequireAdmin = 1 AND @IsAdmin = 0) 
    )