14

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

例如,返回表的行,其中 A 列包含以下任何单词: ('cow','farmer','milk').

当您知道单词是什么时就很容易了,但是我想编写一个存储过程,我可以在其中输入任何字符串数组,并且如果某一行的 A 列包含其中任何一个,它将返回该行。

我希望能够提供:

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

或者

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

或者

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

它必须相对简单,但我一生都无法弄清楚。我在 SQL Server 2008 上

4

6 回答 6

16

一种简单的方法:

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

在 SQL 2008 中执行此操作的最佳方法是使用表值参数

于 2012-08-16T23:45:15.010 回答
4

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

CREATE TYPE dbo.FarmItems AS TABLE(Item VARCHAR(32));
GO

CREATE PROCEDURE dbo.FindFarmItems
  @List dbo.FarmItems READONLY
AS
BEGIN
  SET NOCOUNT ON;

  SELECT t.col1, t.col2, ...
    FROM dbo.table AS t
    INNER JOIN @List AS L
    ON t.columnA = L.Item;
END
GO

然后在 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...
}
于 2012-08-16T23:50:46.370 回答
3

您可以使用 XML 数据类型将列表数据传递给您的存储过程:

create procedure dbo.LookItUp

  @idList xml

as

  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
go

简单的!

于 2012-08-17T00:22:07.977 回答
3

我有同样的困境,并想出了以下。例如,如果 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

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

希望这可以帮助。

于 2014-04-05T05:57:05.633 回答
1

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

选项 1 - 快速而肮脏(我不推荐它)
将值作为字符串传递并将其添加到动态 SQL 语句中。

CREATE PROCEDURE MyProc
  @Values varchar(1000)
AS

DECLARE @SQL VARCHAR(2000)

SET @SQL = 'SELECT blahblah WHERE SomeField IN (' + @Values + ')'

-- Execute the statement and return the result

END

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

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

CREATE TABLE #MyTempTable
-- Fields...

INSERT INTO #MyTempTable
-- Insert the values

CREATE PROCEDURE MyProc
  @Values varchar(1000)
AS

SELECT 
  SomeFields
FROM
  MyTable
  JOIN
  #MyTempTable ON
    -- Add join clause

END

此解决方案可能会更好地扩展。

正如其他人所建议的那样,您还可以使用内存表(我个人避免使用,因为我从来没有对它们很幸运,它们的性能总是比临时表差)或表参数,但您必须事先声明其类型.

于 2012-08-16T23:54:03.083 回答
-1

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

这是我如何做到这一点的完整示例:

create table #bar (foo varchar(20))

insert into #bar (foo) values('cow')
insert into #bar (foo) values('cat')

select foo from #bar
where foo in ('cow','farmer','milk')

drop table #bar
于 2017-07-10T14:46:32.140 回答