在我的表中,我有一个varchar列,可以存储多个值。我的桌子的一个例子:
RecNum | Title | Category
-----------------------------------------
wja-2012-000001 | abcdef | 4,6
wja-2012-000002 | qwerty | 1,3,7
wja-2012-000003 | asdffg |
wja-2012-000004 | zxcvbb | 2,7
wja-2012-000005 | ploiuh | 3,4,12
Category
列中的值指向另一个表。
如果我想在“类别”列中检索值为1,3,5,6,8的行,如何返回相关行?
当我尝试使用IN时,转换varchar值时,我得到转换失败' 1,3,5,6,8'到数据类型int'错误。
答案 0 :(得分:2)
将类别分解为单独的表将是更好的设计,如果这是您可以进行的更改...否则,您可以创建一个函数将值拆分为整数表,如下所示:
CREATE FUNCTION dbo.Split(@String varchar(8000), @Delimiter char(1))
returns @temptable TABLE (id int)
as
begin
declare @idx int
declare @slice varchar(8000)
select @idx = 1
if len(@String)<1 or @String is null return
while @idx!= 0
begin
set @idx = charindex(@Delimiter,@String)
if @idx!=0
set @slice = left(@String,@idx - 1)
else
set @slice = @String
if(len(@slice)>0)
insert into @temptable(id) values(convert(int, @slice))
set @String = right(@String,len(@String) - @idx)
if len(@String) = 0 break
end
return
end
然后从您的查询中调用它:
SELECT ...
FROM ...
WHERE @SomeID IN (SELECT id FROM dbo.Split(Category, ','))
或者,如果您要提供类别列表作为输入参数(例如“1,3,5,6,8”),并返回表格中包含至少其中一个值的所有记录,你可以使用这样的查询:
SELECT ...
FROM ...
WHERE
EXISTS (
select 1
from dbo.Split(Category, ',') s1
join dbo.Split(@SearchValues, ',') s2 ON s1.id = s2.id
)
答案 1 :(得分:1)
你可以这样做
声明@var varchar(30);设置@ var ='2,3';
exec('select * from Category_Id in('+ @ var +')')
答案 2 :(得分:0)
试试这个解决方案:
CREATE TABLE test4(RecNum varchar(20),Title varchar(10),Category varchar(15))
INSERT INTO test4
VALUES('wja-2012-000001','abcdef','4,6'),
('wja-2012-000002','qwerty','1,3,7'),
('wja-2012-000003','asdffg',null),
('wja-2012-000004','zxcvbb','2,7'),
('wja-2012-000005','ploiuh','3,4,12')
select * from test4
Declare @str varchar(25) = '1,3,5,6,8'
;WITH CTE as (select RecNum,Title,Category from test4)
,CTE1 as (
select RecNum,Title,RIGHT(@str,LEN(@str)-CHARINDEX(',',@str,1)) as rem from CTE where category like '%'+LEFT(@str,1)+'%'
union all
select c.RecNum,c.Title,RIGHT(c1.rem,LEN(c1.rem)-CHARINDEX(',',c1.rem,1)) as rem from CTE1 c1 inner join CTE c
on c.category like '%'+LEFT(c1.rem,1)+'%' and CHARINDEX(',',c1.rem,1)>0
)
select RecNum,Title from CTE1
答案 3 :(得分:-1)
正如其他人所提到的,您的表设计违反了基本的数据库设计原则,如果无法绕过它,您可以使用少量代码(下面的示例)对表进行规范化,然后与另一个表联接。你走了:
数据:
CREATE TABLE data(RecNum varchar(20),Title varchar(10),Category varchar(15))
INSERT INTO data
VALUES('wja-2012-000001','abcdef','4,6'),
('wja-2012-000002','qwerty','1,3,7'),
('wja-2012-000003','asdffg',null),
('wja-2012-000004','zxcvbb','2,7'),
('wja-2012-000005','ploiuh','3,4,12')
此函数采用逗号分隔的字符串并返回一个表:
CREATE FUNCTION listToTable (@list nvarchar(MAX))
RETURNS @tbl TABLE (number int NOT NULL) AS
BEGIN
DECLARE @pos int,
@nextpos int,
@valuelen int
SELECT @pos = 0, @nextpos = 1
WHILE @nextpos > 0
BEGIN
SELECT @nextpos = charindex(',', @list, @pos + 1)
SELECT @valuelen = CASE WHEN @nextpos > 0
THEN @nextpos
ELSE len(@list) + 1
END - @pos - 1
INSERT @tbl (number)
VALUES (convert(int, substring(@list, @pos + 1, @valuelen)))
SELECT @pos = @nextpos
END
RETURN
END
然后,你可以做这样的事情来“规范化”表格:
SELECT *
FROM data m
CROSS APPLY listToTable(m.Category) AS t
where Category is not null
然后使用上述查询的结果与“其他”表连接。例如(我没有测试此查询):
select * from otherTable a
join listToTable('1,3,5,6,8') b
on a.Category = b.number
join(
SELECT *
FROM data m
CROSS APPLY listToTable(m.Category) AS t
where Category is not null
) c
on a.category = c.number