【问题标题】:SQL search by multiple lists of values for multiple columns通过多个列的多个值列表进行 SQL 搜索
【发布时间】:2018-10-09 18:57:50
【问题描述】:

我的问题可能有点幼稚,但我以前从未使用过数据库。我是一名 .NET 工程师,我使用 Dapper 访问 SQL Server 数据库。

情况如下:我有一个非规范化表,用于持久化几种类型的实体。每个都有一个复合键(type、id、owner_id)并且键的每一行都是字符串类型(但这并不重要)。而且,假设我正在向数据库写入不同用户的许多兴趣(批量发布)。为了不重复,我需要进行查询并确定哪些已经存在于数据库中。

所以,我的 InterestService 类中有这段代码:

private IEnumerable<Interest> GetAlreadyExistingInterestsFor(IEnumerable<Interest> interestsForCreating) =>
    _interestRepository.GetInterests(interestsForCreating.Select(interest => interest.Id).ToList(),
                                     interestsForCreating.Select(interest => interest.UserId).ToList());

之后我有一些逻辑等等。这不重要。

InterestRepository 方法 GetInterests 看起来像这样:

public GetInterests(IList<string> interestIds, IList<string> userIds) 
{
    var query = @"SELECT type, id, owner_id
                  FROM entities
                  WHERE type = 'interest'
                   AND id IN @InterestIds
                   AND owner_id IN @UserIds";
    return _dbContext.ExecuteQuery(query, new { InterestIds = interestIds, UserIds = userIds });
}

代码可能有错误,因为现在我无法访问工作环境,但我认为这个想法很清楚。因此,问题是这是否是进行查询的最佳方法。如果有更好的,那是什么。

【问题讨论】:

  • 你有能力使用存储过程吗?
  • 不,那样不行。您应该考虑使用表值参数。然后你可以对你的两个表参数使用内连接。
  • 如果您正在寻找建议,我会研究实体框架。简化编码的存储库部分。由于您已经有一个数据库,您将使用 db-first 方法。 docs.microsoft.com/en-us/ef/ef6/modeling/designer/workflows/…
  • @DavidGreilach 没有。我正在考虑存储过程和触发器,但不想使用它们。
  • @SeanLange 我没明白。你能更广泛地描述你的观点吗?

标签: c# sql .net sql-server dapper


【解决方案1】:

基本上你可以简单地做这篇文章中所做的事情,但是对于表值参数使用两组而不是一组。 Using Dapper, how do I pass in the values for a sql type as param?

它使用一个存储过程和一个 sql 表值参数。

【讨论】:

  • 在那之后,我就有能力写这样的查询了? var query = @"SELECT * FROM entities e INNER JOIN @tmp t ON e.id = t.id" AND e.owner_id = t.owner_id; 抱歉,如果我犯了错误,我昨天就开始使用这个级别的数据库了 :)
【解决方案2】:

如果stored procedure 不是一个选项,那么您可以使用以下方法之一。

  1. interestIdsuserIds 转换为字符串
    string interests = "(1, 2, 3, 4)" 如果列表仅包含数字,('a1', 'b1', 'c2') 如果它们是字符串。

然后将它们内联到您的查询中

var query = @"SELECT type, id, owner_id
              FROM entities
              WHERE type = 'interest'
               AND id IN "+ interests
               + " AND owner_id IN " + users;

这种方法被认为是不好的做法,并且会导致 SQL 注入攻击(在用户输入的情况下)。使用它如果绝对确定您的数据。

  1. SQL Server 2016+ 有一个内置函数string_split 可以在这里使用。该函数将带有分隔符的字符串拆分为表格t(value)
    再次将列表转换为字符串string interests="a1, a2, b3, c4";(此处没有单引号)

查询

var query = @"SELECT type, id, owner_id
              FROM entities
              WHERE type = 'interest'
               AND id IN (select value from string_split(@interests,','))
               AND owner_id IN (select value from string_split(@users,','))";

对于早期版本,您可以创建具有相同功能的 UDF。

create function dbo.split_string(@input varchar(max), @separator varchar(2))
returns table as
return
(with cte as(
select cast('<v>'+ REPLACE(@input, @separator, '</v><v>') +'</v>' as xml) x
)
select t.v.value('.[1]', 'varchar(max)') [value]
from cte
cross apply x.nodes('v') t(v))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多