Sql 在逗号分隔列表中为不同表的每条记录查找值

Sql 在逗号分隔列表中为不同表的每条记录查找值,sql,tsql,sql-server-2012,Sql,Tsql,Sql Server 2012,我们有一张桌子,上面放着我们的客户、他们的产品和他们订阅的城市。“城市”字段是以逗号分隔的数字列表 他们需要一个存储过程来查找所有拥有他们传入的特定城市id的客户,但他们希望能够传入多个城市id 范例 他们希望找到订阅22和/或900的所有客户(两者都是不同的城市) 我需要所有在逗号分隔列表中有一个或另一个或两个城市的客户 所以我需要一种方法来搜索列表中的第一个值,然后再搜索列表中的第二个值。我曾考虑使用递归CTE,但我需要加入City表(我创建的临时表用于分隔它们传递的城市ID列表),我不能

我们有一张桌子,上面放着我们的客户、他们的产品和他们订阅的城市。“城市”字段是以逗号分隔的数字列表

他们需要一个存储过程来查找所有拥有他们传入的特定城市id的客户,但他们希望能够传入多个城市id

范例 他们希望找到订阅22和/或900的所有客户(两者都是不同的城市)

我需要所有在逗号分隔列表中有一个或另一个或两个城市的客户

所以我需要一种方法来搜索列表中的第一个值,然后再搜索列表中的第二个值。我曾考虑使用递归CTE,但我需要加入City表(我创建的临时表用于分隔它们传递的城市ID列表),我不能

当他们放入city_id时,我将该列表分离到一个表中,该表将每个city id作为临时表中自己的记录。帮忙

请不要说停止存储逗号分隔的列表。。。我不能改变我们系统的这部分功能,这是没有帮助的。(在寻找这个问题的答案时,我已经看过很多次了)

我会在上面搜索类似的东西,寻找20或900,这是一个非常小的样本。一切都很简单,我知道在那里该做什么。当试图寻找多个城市id时,它会在列表中搜索,这是一个问题。我能够在只寻找一个城市id的情况下进行搜索,它会做多个,这就是杀手

我一开始就是这样做的:

CREATE TABLE #City 
     ( Order_ID INT
     , City_ID  VARCHAR(100)
     , FirstCitySearchText VARCHAR(100) NULL
     , LastCitySearchText VARCHAR(100)  NULL
     , OnlyCitySearchText VARCHAR(100)  NULL
       PRIMARY KEY (Order_ID, City_ID)
     )

INSERT INTO #City
SELECT i.listpos
     , i.quotedtext
     , NULL
     , NULL
     , NULL
  FROM opiscommon.dbo.SplitCommaSeparatedList(@City_IDs) i

UPDATE c
   SET c.FirstCitySearchText = '%'  + CAST(c.City_ID AS VARCHAR)+ ',%'
     , c.LastCitySearchText = '%,' + CAST(c.City_ID AS VARCHAR) + '%'
     , c.OnlyCitySearchText = '%,'  + CAST(c.City_ID AS VARCHAR) + ',%'
  FROM #City c

有时你会被别人糟糕的设计决策所困扰。您应该了解在列表中存储ID、以字符串形式存储数值以及没有声明外键关系的外键是多么糟糕

但是,当你陷入困境时,有一些方法。下面是一个使用类似于的
的方法:

where ',' + list + ',' like '%,22,%' or
      ',' + list + ',' like '%,900,%'

这是22的逻辑。重复所有数字

where city = '22'  -- exact match
or city like '22,%' -- first item in list
or city like '%,22,%'  -- middle of list
or city like '%,22' -- last item in list

因此,我最终解决了我的问题,我加入了谈判桌,就像这样:

JOIN #CityIDs c
  ON cpcpp.CUST_PROD_PARM_VAL LIKE '' + c.FirstCitySearchText + ''
  OR cpcpp.CUST_PROD_PARM_VAL LIKE '' + c.LastCitySearchText + ''
  OR cpcpp.CUST_PROD_PARM_VAL LIKE '' + c.OnlyCitySearchText + ''
  OR cpcpp.CUST_PROD_PARM_VAL LIKE '' + c.City_ID + ''
  OR cpcpp.CUST_PROD_PARM_VAL LIKE 'ALL'
这些搜索文本字段是:

UPDATE c
   SET c.FirstCitySearchText = CAST(c.City_ID AS VARCHAR(100))+ ',%'
     , c.LastCitySearchText = '%,' + CAST(c.City_ID AS VARCHAR(100))
     , c.OnlyCitySearchText = '%,'  + CAST(c.City_ID AS VARCHAR(100)) + ',%'
  FROM #CityIDs c
我无法使用发布的where子句,因为我不确定如何加入表以获取城市ID,因此我使用where子句作为联接来加入它们


这不是一个好的解决方案,但它是迄今为止唯一有效的解决方案。我得到了预期的结果,存储过程只需要20秒就可以运行,这被认为是一个胜利。

您应该首先考虑数据规范化。显示示例数据我曾想过为每个客户分离逗号列表,但我一次搜索数百万条记录,以及列表中有30、50多个城市的客户。如果可能的话,我想再找一个。由于我们数据的敏感性,我不知道我能提供什么。但我会努力的,这不是问题。事实上,如果数据被规范化,它的运行速度会比您现在尝试的要快。这里的每个人都是正确的-不要担心您可能需要存储/搜索多少行,您需要考虑SQL Server如何最有效地工作,并且当这些行被索引时,它的工作效率比解析逗号分隔的字符串要好得多,相信我。另外,这个问题是我无法预测它们将传入什么数字,我必须创建一个存储过程来处理这个问题。这不是一次性的请求。我明白了,我将不得不使用,这就是为什么我做临时表的方式,我做了。它使用的是下面回答的2给出的方法,包括他们传递给存储过程的任何数字和数字数量。如果他们试图一次添加20个或更多id,这将不起作用,这是可行的。@MacWilson08不确定问题出在哪里。如果他们同时添加多个值,请使用TVP,现在您可以连接到它,而不是手动构造类似于单个语句的语句。我无法使用城市ID连接该表,因为没有字段可以连接到任何其他表。@MacWilson08您甚至查过TVP是什么吗?将
list
所在的表连接到传入的TVP参数,该参数的作用类似于一个表。@MacWilson08。这在20个以上ID的情况下可以正常工作。
where
子句变长了,但是这个想法很有效。如果他们试图一次添加20个或更多id,这将不起作用,哪一个是可行的。使用此解决方案,20个或更多的城市ID如何不可行?那么您如何将20个城市ID放入
#cityID
?我们通过以下方法来实现这一点:当存储过程被称为EXEC usp_ProcedureName@cityID='22900'时,当调用存储过程时,城市ID被传递给VARCHAR。然后,我使用我们在house中创建的函数分割城市ID,并将它们插入临时表中。您可以在问题部分看到拆分。
UPDATE c
   SET c.FirstCitySearchText = CAST(c.City_ID AS VARCHAR(100))+ ',%'
     , c.LastCitySearchText = '%,' + CAST(c.City_ID AS VARCHAR(100))
     , c.OnlyCitySearchText = '%,'  + CAST(c.City_ID AS VARCHAR(100)) + ',%'
  FROM #CityIDs c