2

私のテーブルには、複数の値が格納される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に変換するときに変換に失敗しました」というエラーが発生します。

4

4 に答える 4

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」など) として提供し、これらの値の少なくとも 1 つを含むテーブル内のすべてのレコードを返す場合は、次のようにすることができます。次のようなクエリを使用します。

SELECT ...
FROM ...
WHERE
    EXISTS (
        select 1
        from dbo.Split(Category, ',') s1
        join dbo.Split(@SearchValues, ',') s2 ON s1.id = s2.id
    )
于 2012-08-01T04:37:22.833 に答える
1

あなたはこのようにすることができます

@var varchar(30); を宣言します。@var='2,3'; を設定します。

exec('select * from category where Category_Id in ('+@var+')')

于 2012-08-01T07:52:06.937 に答える
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
于 2012-08-01T05:15:21.977 に答える
-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
于 2012-08-01T06:17:55.880 に答える