2012-10-16 176 views
1

我有一个由逗号分隔的分隔数字的varchar字符串,我想在我的SQL脚本中使用它,但我需要与数据库中的bigint字段进行比较。需要知道它转换:将逗号分隔字符串转换为SQL Server中的bigint

DECLARE @RegionID varchar(200) = null 
SET @RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' 

SELECT a.ClassAdID, -- 1 
     a.AdURL,  -- 2 
     a.AdTitle,  -- 3 
     a.ClassAdCatID, -- 4 
     b.ClassAdCat, -- 5 
     a.Img1,   -- 6 
     a.AdText,  -- 7 
     a.MemberID,  -- 9 
     a.Viewed,  -- 10 
     c.Domain,  -- 11 
     a.CreateDate -- 12 
     FROM ClassAd a 
     INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID 
     INNER JOIN Region c ON c.RegionID = a.RegionID 
     AND a.PostType = 'CPN' 
     AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0 
     AND a.RegionID IN (@RegionID) 
     AND Viewable = 'Y' 

这失败,出现以下错误:

Error converting data type varchar to bigint. 

RegionID在数据库是一个BIGINT场..需要将varchar转换为bigint ..任何想法。 。?

提前许多感谢,

neojakey

回答

3

创建此功能:

CREATE function [dbo].[f_split] 
(
@param nvarchar(max), 
@delimiter char(1) 
) 
returns @t table (val nvarchar(max), seq int) 
as 
begin 
set @param += @delimiter 

;with a as 
(
select cast(1 as bigint) f, charindex(@delimiter, @param) t, 1 seq 
union all 
select t + 1, charindex(@delimiter, @param, t + 1), seq + 1 
from a 
where charindex(@delimiter, @param, t + 1) > 0 
) 
insert @t 
select substring(@param, f, t - f), seq from a 
option (maxrecursion 0) 
return 
end 

改变这一部分:

AND a.RegionID IN (select val from dbo.f_split(@regionID, ',')) 

更改此为更好的整体性能:

AND DATEDIFF(d, 0, GETDATE()) <= ExpirationDate 
+0

精美地工作..非常感谢您的帮助..! – neojakey

1

您的查询不知道,那些都是独立的值,你可以使用动态SQL这样的:

DECLARE @RegionID varchar(200) = null 
SET @RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' 

declare @sql nvarchar(Max) 

set @sql = 'SELECT a.ClassAdID, -- 1 
     a.AdURL,  -- 2 
     a.AdTitle,  -- 3 
     a.ClassAdCatID, -- 4 
     b.ClassAdCat, -- 5 
     a.Img1,   -- 6 
     a.AdText,  -- 7 
     a.MemberID,  -- 9 
     a.Viewed,  -- 10 
     c.Domain,  -- 11 
     a.CreateDate -- 12 
     FROM ClassAd a 
     INNER JOIN ClassAdCat b ON b.ClassAdCAtID = a.ClassAdCAtID 
     INNER JOIN Region c ON c.RegionID = a.RegionID 
     AND a.PostType = ''CPN'' 
     AND DATEDIFF(d, GETDATE(), ExpirationDate) >= 0 
     AND a.RegionID IN ('[email protected]+') 
     AND Viewable = ''Y''' 

exec sp_executesql @sql 
1

我有时用这个apporach,并发现它非常好。 它transfors以逗号分隔的字符串转换成AUX表(称为#ARRAY),然后根据查询的AUX表主表:

declare @RegionID varchar(50) 
SET @RegionID = '853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' 
declare @S varchar(20) 
if LEN(@RegionID) > 0 SET @RegionID = @RegionID + ',' 
CREATE TABLE #ARRAY(region_ID VARCHAR(20)) 

WHILE LEN(@RegionID) > 0 BEGIN 
    SELECT @S = LTRIM(SUBSTRING(@RegionID, 1, CHARINDEX(',', @RegionID) - 1)) 
    INSERT INTO #ARRAY (region_ID) VALUES (@S) 
    SELECT @RegionID = SUBSTRING(@RegionID, CHARINDEX(',', @RegionID) + 1, LEN(@RegionID)) 
END 

select * from your_table 
where regionID IN (select region_ID from #ARRAY) 

它避免你ahving来连接的查询字符串,然后使用EXEC执行它,我不认为这是一个非常好的方法。

如果需要两次运行的代码,你将需要删除临时表

0

我想答案应该保持简单。
尝试使用CHARINDEX这样的:

DECLARE @RegionID VARCHAR(200) = NULL 

SET @RegionID = 
'853,834,16,467,841,460,495,44,859,457,437,836,864,434,86,838,458,472,832,433,142,154,159,839,831,469,442,275,840,299,446,220,300,225,227,447,301,450,230,837,441,835,302,477,855,411,395,279,303' 

SELECT 1 
WHERE Charindex('834', @RegionID) > 0 

SELECT 1 
WHERE Charindex('999', @RegionID) > 0 

CHARINDEX在大字符串变量找到值,它会返回它的位置,否则返回0。
以此作为搜索工具。

0

更改此查询的最简单方法是用字符串函数替换IN函数。以下是我使用LIKE(这是数据库之间移植)认为最安全的方法:

AND ','[email protected]+',' like '%,'+cast(a.RegionID as varchar(255))+',%' 

或者CHARINDEX

AND charindex(','+cast(a.RegionID as varchar(255))+',', ','[email protected]+',') > 0 

但是,如果你明确地把名单在你的代码,为什么不使用临时表?

declare @RegionIds table (RegionId int); 
insert into @RegionIds 
    select 853 union all 
    select 834 union all 
    . . . 
    select 303 

然后你可以使用表中的IN子句中:

AND a.RegionId in (select RegionId from @RegionIds) 

或在JOIN条款。

0

我喜欢Diego的回答,但我认为我的修改更好一点,因为你声明了一个表变量而不是创建一个实际的表。我知道“in”语句可能有点慢,所以我进行了内连接,因为我仍然需要公司表中的一些信息。

declare @companyIdList varchar(1000) 
set @companyIdList = '1,2,3' 

if LEN(@companyIdList) > 0 SET @companyIdList = @companyIdList + ',' 
declare @CompanyIds TABLE (CompanyId bigint) 
declare @S varchar(20) 
WHILE LEN(@companyIdList) > 0 BEGIN 
    SELECT @S = LTRIM(SUBSTRING(@companyIdList, 1, CHARINDEX(',', @companyIdList) - 1)) 
    INSERT INTO @CompanyIds (CompanyId) VALUES (@S) 
    SELECT @companyIdList = SUBSTRING(@companyIdList, CHARINDEX(',', @companyIdList) + 1, LEN(@companyIdList)) 
END 

select d.Id, d.Name, c.Id, c.Name 
from [Division] d 
    inner join [Company] c on d.CompanyId = c.Id 
    inner join @CompanyIds cids on c.Id = cids.CompanyId 
相关问题