我正在尝试将存储列表项(逗号分隔)的数据库字段与不幸的是一个也是列表项的变量进行比较。
例子:
在这种情况下,一个用户可以属于多个组,内容访问也分配给多个组。
contentid | group
(1) (c,d)
(2) (a,c)
(3) (b)
所以,我需要选择用户在组(a,c)中的所有内容。在这种情况下,应该返回 contentid 1,2。
这是 SQL 2008 的安全但缓慢的解决方案
BEGIN
-- setup
DECLARE @tbl TABLE (
[contentid] INT
,[group] VARCHAR(MAX)
)
INSERT INTO @tbl VALUES
(1, 'c,d')
,(2, 'a,c')
,(3, 'd')
-- send your request as simple xml
DECLARE @param XML
SET @param = '<g>a</g><g>c</g>'
-- query
SELECT DISTINCT contentid
FROM @tbl t
INNER JOIN @param.nodes('/g') AS t2(g)
ON ',' + t.[group] + ',' LIKE '%,' + t2.g.value('.', 'varchar(max)') + ',%'
END
您只需将查询作为 XML 片段而不是逗号分隔列表传递。
如果您的组名是单个字符,或者您可以确定名称不是彼此的字符子集(即:GroupA、GroupAB),则可以优化查询。
ON t.[group] LIKE '%' + t2.g.value('.', 'varchar(max)') + '%'
如果您使用的是没有 XML 解析功能的 RDBMS,则必须使用字符串将查询拆分为临时表并以这种方式工作。
您真的不应该在列中使用逗号分隔值。如果 [group] 列仅包含一个值,并且您在组合(contentid,group)上有重复的条目,并且具有 UNIQUE 约束,那会好得多。
您可能会发现这个问题和答案很有用:如何拆分字符串以便访问项目 x?
或者你总是可以使用这样的东西:
create function SplitString(
@string varchar(max),
@delimiter char(1)
)
returns @items table (item varchar(max))
as
begin
declare @index int set @index = 0
if (@delimiter is null) set @delimiter = ','
declare @prevdelimiter int set @prevdelimiter = 0
while (@index < len(@string)) begin
if (substring(@string, @index, 1) = @delimiter) begin
insert into @items
select substring(@string, @prevdelimiter, @index-@prevdelimiter)
set @prevdelimiter = @index + 1
end
set @index = @index + 1
end
--last item (or only if there were no delimiters)
insert into @items
select substring(@string, @prevdelimiter, @index - @prevdelimiter + 1)
return
end
go
declare @content table(contentid int, [group] varchar(max))
insert into @content
select 1, 'c,d'
union
select 2, 'a,c'
union
select 3, 'b'
declare @groups varchar(max) set @groups = 'a,c'
declare @grouptable table(item varchar(max))
insert into @grouptable
select * from dbo.SplitString(@groups, ',')
select * From @content
where (select count(*) from @grouptable g1 join dbo.SplitString([group], ',') g2 on g1.item = g2.item) > 0