0

目前我有一个表,它有一个 user_type 列,并且只有当用户匹配该 user_type 时才会显示该行。我想让它可以设置多个 user_types 而不复制数据并且不创建另一个表。我认为我可以将列从 int 转换为 varchar,并使其成为逗号分隔的用户类型 ID 列表。

到目前为止,它一直运作良好。只要我事先知道 user_type 是什么,因为这样我就可以在检查是否应该向用户显示时专门使用它:

SELECT *
FROM perm
WHERE user_type='50'
    OR user_type LIKE '50,%'
    OR user_type LIKE '%,50,%'
    OR user_type LIKE '%,50'

当我尝试加入关于值的表时,问题就出现了。当我尝试使用IN

SELECT p.*
FROM perm p
JOIN [user] u ON u.type IN (p.user_type)

我得到了错误:Conversion failed when converting the varchar value '50,40,30' to data type int.所以我决定我会回到LIKE我上面一直使用的方法:

SELECT p.*
FROM perm p
JOIN [user] u ON (
    u.type LIKE p.user_type
    OR u.type LIKE (p.user_type + ',%')
    OR u.type LIKE ('%,' + p.user_type + ',%')
    OR u.type LIKE ('%,' + p.user_type)
)

这仅返回仅具有一种用户类型值的结果。有没有办法将逗号分隔的列表转换为与IN命令一起使用?或者有什么方法可以进行动态LIKE论证?

4

3 回答 3

2

有许多 TSQL 代码示例将分隔的字符串拆分为“数组”或表变量。

例如使用此函数:https ://stackoverflow.com/a/10914602/961695 ,您可以将查询重写为:

SELECT p.*
FROM perm p JOIN dbo.splitstring('50,40,30') s
ON p.user_type = s.name

(并避免使用动态 SQL)

于 2014-05-23T21:31:49.423 回答
0

我会给你一种适用于你现在所拥有的方法(可怕)和正确的方法(正如@paqogomez 建议的那样)。这种方式涉及滥用PARSENAME,并且仅适用于 SQL Server,并且仅当 perm.user_type 具有 4 个或更少的用户类型时。还有另一种方法没有 4 的限制——它涉及滥用 SQL Server 的 XML 解析——但它更复杂、更慢,所以我不会展示那个:

我还假设您只想为特定用户列出 Perm 中的行,并且该[user]表具有id主键:

SELECT p.*
FROM [user] u
JOIN perm p ON u.type IN (
    CAST((PARSENAME(REPLACE(p.user_type,',','.'),1)) AS INT),
    CAST((PARSENAME(REPLACE(p.user_type,',','.'),2)) AS INT),
    CAST((PARSENAME(REPLACE(p.user_type,',','.'),3)) AS INT),
    CAST((PARSENAME(REPLACE(p.user_type,',','.'),4)) AS INT)
)
WHERE u.id = ?

更好的方法是 paqogomez 方法,您使用关系表来存储 Perm 的用户类型(假设 Perm 的主键是id

Perm_User_Type
  Perm_id -> Perm.id
  User_type -> [user].type

那么更有效的查询将如下所示:

SELECT p.*
FROM [user] u
JOIN Perm_User_Type put ON u.type = put.User_type
JOIN perm p ON put.Perm_id = p.id
WHERE u.id = ?

当然,在这种情况下,用户类型的数量是没有限制的。

于 2014-05-23T22:01:47.400 回答
-1

我认为没有动态 SQL 就无法做到这一点。就像是:

declare @sql nvarchar(max)

set @sql = '
SELECT p.*
FROM perm p
JOIN [user] u ON u.type IN (''' + p.user_type + ''')'

exec sp_ExecuteSql @sql
于 2014-05-23T21:29:56.550 回答