2016-07-13 54 views
0

我在表中的一个有一个USER_ROLE列,这已经管分离像解析管分隔值

guest|user_Admin|user_guest 
user_Admin|guest 
guest|user_guest|user_Admin 
user_guest|user_Admin 
user_Admin 

我必须从上面的表格,其中有得到角色值管理在它。 我不想整个行都有Admin。

例如,如果列数据是客| user_guest | user_Admin,查询应该只返回user_Admin而不是完整的价值。

我该如何实现它?

+0

你可以写一个case语句,例如'CASE WHEN User_Role LIKE'%user_Admin%'THEN'user_Admin'END'或者如果你只想要user_Admin作为用户角色的用户,那么'SELECT'user_Admin'FROM myTable WHERE User_Role LIKE'%user_Admin%''或类似的东西。 – ZLK

+1

[在sql中管道分隔的列中搜索值的可能重复](http://stackoverflow.com/questions/18767077/search-value-in-column-which-is-pipe-separated-in-sql) –

+0

我不想硬编码价值。我想从数据中推导出它。 – turbo88

回答

-1

这应该工作。它使用游标来处理每个角色。

--- --- UPDATE

更新光标处理以覆盖许多边缘情况。

DECLARE @roles varchar(1000), @ADMININDEX int, @STARTINDEX int, @ENDINDEX int, @TEMP varchar(1000) 

DECLARE MY_CURSOR CURSOR 
    LOCAL STATIC READ_ONLY FORWARD_ONLY 
FOR 
SELECT roles 
FROM test 

OPEN MY_CURSOR 
FETCH NEXT FROM MY_CURSOR INTO @roles 
WHILE @@FETCH_STATUS = 0 
BEGIN 
    --Do something with Id here 
    SET @ADMININDEX = CHARINDEX('Admin',@roles) 
    IF (@ADMININDEX > 0) 
    BEGIN 
     SET @ADMININDEX += 5 
     SET @TEMP = CHARINDEX('|', SUBSTRING(@roles, @ADMININDEX, LEN(@roles))) 
     IF @TEMP = 0 
      SET @ENDINDEX = LEN(@roles) + 1 
     ELSE 
      SET @ENDINDEX = @TEMP - 1 + @ADMININDEX 
     SET @roles = SUBSTRING(@roles, 0, @ENDINDEX) 
     SET @STARTINDEX = LEN(@roles) - CHARINDEX('|', REVERSE(@roles)) + 2 
     IF (@STARTINDEX>@ADMININDEX) 
      PRINT @roles 
     ELSE 
      PRINT SUBSTRING(@roles, @STARTINDEX, @ENDINDEX) 
    END 
    FETCH NEXT FROM MY_CURSOR INTO @roles 
END 
CLOSE MY_CURSOR 
DEALLOCATE MY_CURSOR 
+0

这在技术上只适用于用户角色类似'xyz_admin'的情况。如果用户的角色类似于“admin_xyz”,则不会得到正确的结果。它也不适用于没有管理员角色的用户(如果这很重要)。 – ZLK

+0

@ZLK这些情况是非常容易绕过一些小的修改。我只是根据提供的样本奠定了基础。 – 10100111001

+0

为什么downvote被给出的原因将是有帮助的。 – 10100111001

1

首先,我要告诉你你应该怎么做......规范你的表。

如果有问题的表是用户角色表,那么将您的user_role列拆分为单个值。如果它是包含其他列的较大表的一部分,则应使用单独的表来存储用户角色信息。我还建议为每个值分配不同的级别,因此您不必分析字符串。

例如,有一个像

CREATE TABLE userRoles (userID INT, userRole INT); 

一个user_roles表...然后有一个角色表所示:

CREATE TABLE Roles (userRole INT IDENTITY(1, 1), roleDescription VARCHAR(255), roleLevel INT); 
INSERT Roles (roleDescription, roleLevel) VALUES ('guest', 1), ('user_guest', 2), ('user_Admin', 3); 

......这样一来,你可以找到做管理员角色加入并寻找3级而不是解析字符串。如果你的表很小,没有什么大不了的,但是你的表越大,解析字符串的成本就越高。通过适当的索引,这将成为检索所需数据的最快方法,同时还可以根据需要轻松更改数据(需要更改角色名称?没问题...在Roles表中编辑roleDescription)。

但是做不到这一点,这里有一对夫妇的解决方案,你可以考虑......

declare @1 table (ID INT IDENTITY(1, 1), User_Role varchar(255)); 
insert @1 (User_Role) values ('guest|hello_Kitty_Admin|user_guest'),('user_Admin_zzz|guest'),('guest|user_guest|greatest_admin_of_all_time'),('user_guest|user_Admin2'),('user_Admin'),('regular_user'); 
with t as (
    select id, user_role, left(User_Role, charindex('admin', User_Role) + isnull(nullif(charindex('|', substring(User_Role, charindex('admin', User_Role), len(User_Role))), 0) - 2, len(User_Role))) zzz 
    from @1) 
select id, isnull(right(zzz, isnull(nullif(charindex('|', reverse(zzz)), 0) - 1, len(zzz))), user_role) adminrole 
from t; 

...上述所有正在做的是解析您USER_ROLE柱,发现其中admin是和获取一切行括号之间该值(如果不存在,它只是返回全额USER_ROLE)

declare @2 table(ID INT IDENTITY(1, 1), User_Role varchar(255)); 
insert @2 (User_Role) values ('guest|hello_Kitty_Admin|user_guest'),('user_Admin_zzz|guest'),('guest|user_guest|greatest_admin_of_all_time'),('user_guest|user_Admin2'),('user_Admin'),('regular_user'); 
with cte as (
    select id, user_role, substring(user_role, 1, isnull(nullif(charindex('|', user_role), 0) - 1, len(user_role))) roles, nullif(charindex('|', user_role), 0) cindex, 1 L 
    from @2 
    union all 
    select id, user_role, substring(user_role, cindex+1, isnull(nullif(charindex('|', user_role, cindex+1), 0) - 1 - cindex, len(user_role))), nullif(charindex('|', user_role, cindex+1), 0), L + 1 
    from cte 
    where cindex is not null) 
select id, max(isnull(x.y, user_role)) adminrole 
from cte t 
outer apply (
    select min(roles) over (partition by len(roles)) 
    from cte 
    where id = t.id 
    and roles like '%admin%') x(y) 
group by id, x.y 
order by id; 

...这是在做同样的事情,另外一个用不同的方法。

或者您可以使用类似于其他答案的光标,稍作修改。

但真的,正常化!