添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

查询一个SQL字段是否包含多个值中的任何一个

14 人关注

我想查询SQL列的行,看它是否包含多个值中的任何一个。

例如,返回一个表的行,其列A包含以下任何一个词。 ('cow','farmer','milk')

当你知道这些词是什么时,这很容易,但我想写一个sproc,我可以输入任何字符串数组,如果某一行的A列包含其中任何一个,它将返回该行。

我希望能够进货。

('cow','farmer','milk')

('cow','farmer','steak','yikes')

('cow','farmer','three', 'pigs', 'wolf')

这一定是相对简单的,但我却无法弄清楚。 我使用的是SQL Server 2008

3 个评论
能否请你展示一下样本数据?例如,该表是否在每一行都包含单一的数值,或者该表也可以包含一个字符串,如 cow,milk
Matt
对不起,数据将是整个句子,我想看看是否有这些词出现。
你可以试试我的方案,只是把JOIN改成LIKE而不是=。 现在用手机无法正常编辑。
sql
sql-server
sql-server-2008
stored-procedures
Matt
Matt
发布于 2012-08-17
6 个回答
Av Pinzur
Av Pinzur
发布于 2017-07-10
0 人赞同

一个简单的方法。

declare @candidates varchar = '|cow|farmer|three|pigs|wolf|'
select * from TableName where @candidates like '%|' + FieldName + '|%'

在SQL 2008中,最好的方法是使用一个表值参数

+1 - 对这个问题的膝跳反应是使用分割函数,但在这种情况下,它只是没有必要。我想说 LIKE 仍然比TVP更有效,但我不确定,因为我没有在这个用例中直接测试过那些东西,而且我还是要发布一个TVP的答案,以便OP可以测试。
我认为OP想要的是FieldName 包含 其中一个单词的行--这将检查FieldName是否 等于 其中一个单词。
@Blorgbeard 我也把 "包含多个值中的任何一个 "解释为 "其值与任何一个值相对应",但你可能是对的。
我一直在努力让它工作,发现这是因为FieldName对我来说是一个nvarchar(64),而我只是把@candidates声明为nvarchar。如果我明确说明(at)candidates是一个nvarchar(64),然后将其设置为一个列表,那么无论列表的大小如何,都可以工作。
对于 FieldName 的形式是 potato|monkey|pigs|carrot|sandwich ,而你想匹配的原因是它包含 @candidates 中的一个值,是否有类似的解决方案?
Aaron Bertrand
Aaron Bertrand
发布于 2017-07-10
0 人赞同

SQL Server不知道什么是 "数组"。你可以写一个拆分表值的函数,把每个值变成一行,然后针对基表进行连接,但与Av的答案相比,这绝对是次优的。或者你可以用一个表值参数来测试。 与所有的拆分技术相比, TVP 绝对是表现最好的,甚至是CLR

CREATE TYPE dbo.FarmItems AS TABLE(Item VARCHAR(32));
CREATE PROCEDURE dbo.FindFarmItems
  @List dbo.FarmItems READONLY
BEGIN
SET NOCOUNT ON;
  SELECT t.col1, t.col2, ...
    FROM dbo.table AS t
    INNER JOIN @List AS L
    ON t.columnA = L.Item;

然后在C#中,你只需用你的 "数组 "构建一个DataTable,并将其传入。

DataTable dt = new DataTable();
dt.Columns.Add("Item", typeof(string));
dt.Rows.Add("cow");
dt.Rows.Add("farmer");
using (SqlConnection conn = new ...)
    SqlCommand c = new SqlCommand("dbo.FindFarmItems", conn);
    2.CommandType = CommandType.StoredProcedure;
    SqlParameter tvp = c.Parameters.AddWithValue("@List", dt);
    tvp.SqlDbType = SqlDbType.Structured;
    // execute, get a reader, etc...
Nicholas Carey
Nicholas Carey
发布于 2017-07-10
0 人赞同

你可以使用XML数据类型来传递列表数据给你的存储过程。

create procedure dbo.LookItUp
  @idList xml
declare @lookup table
    id int not null
  insert @lookup (id)
  select distinct t.id.value('.','int')
  from @idList.nodes('/ids/id') as t( id )
  where t.id is not null
select *
from dbo.my_data_table t
  join @lookup           lu on lu.id = t.object_id
  return 0
raeldor
raeldor
发布于 2017-07-10
0 人赞同

我也遇到了同样的困境,并想出了以下办法。 例如,如果table_a包含('My Cow', 'My Goat', 'My Dog'),table_b包含('Dog', 'Cow'),那么...

create table #table_a (field1 varchar(128))
insert into #table_a values('My Cow')
insert into #table_a values('My Goat')
insert into #table_a values('My Dog')
create table #table_b (field1 varchar(128))
insert into #table_b values('Dog')
insert into #table_b values('Cow')
select * from #table_a table_a where (select count(*) from #table_b table_b where charindex(table_b.field1, table_a.field1) > 0) > 0

返回('我的牛','我的狗')。

希望这有帮助。

Diego
Diego
发布于 2017-07-10
0 人赞同

你不能将数组传递给存储过程,因为数组在TSQL中不存在。你有几个选择,我给你其中的两个。

选项1--快速和肮脏 (我不建议这样做)。
以字符串的形式传递数值并将其添加到动态SQL语句中。

CREATE PROCEDURE MyProc
  @Values varchar(1000)
DECLARE @SQL VARCHAR(2000)
SET @SQL = 'SELECT blahblah WHERE SomeField IN (' + @Values + ')'
-- Execute the statement and return the result

除了明显的SQL注入漏洞外,这种方法对大数据集不起作用,而且性能也不太理想。此外,如果任何值包含一个逗号,它也不会起作用。我真的不推荐这种方法,尽管它对于快速测试可能是有用的。

方案2--一个更灵活的解决方案
将所有的值存储在一个临时表中,你将在存储过程中引用该表。

CREATE TABLE #MyTempTable
-- Fields...
INSERT INTO #MyTempTable
-- Insert the values
CREATE PROCEDURE MyProc
  @Values varchar(1000)
SELECT 
  SomeFields
  MyTable
  #MyTempTable ON
-- Add join clause

这种解决方案可能会有更好的扩展。

正如其他人所建议的,你也可以使用内存表(我个人避免使用,因为我从来没有什么运气,它们的表现总是比临时表差),或一个表参数,但你必须事先声明其类型。

有了新的信息,第一个解决方案不起作用,因为你不能结合LIKE和IN。对于第二个方案,代码的关键部分完全缺失--如何将数值数组(可能来自一个应用程序)放入#temp表中。
OP在原帖中没有写 "LIKE",因此我没有使用。很明显,现在他澄清了他的需求,我的解决方案就不再适用了。
Pa0l0
Pa0l0
发布于 2017-07-10
0 人赞同

你可以简单地使用WHERE列IN(逗号分隔的字符串)。

这里是我的完整例子,如何做到这一点。

create table #bar (foo varchar(20))
insert into #bar (foo) values('cow')
insert into #bar (foo) values('cat')