c#数据库检索信息

本文关键字:信息 检索 数据库 | 更新日期: 2023-09-27 18:24:23

我想知道一些事情。

我试图检索2个文件。

一个是用于组2的寄存器,一个用于组10。

所以字段是Files.Group.

一个用户注册到组1和组10。

这是我用来检索文件的查询。

SELECT Files.Id, Files.Name, Files.Date, Files.Path, Files.[Group] FROM Files WHERE Files.[Group] = " + param + "ORDER BY Files.Id DESC"

Param是一个获得群组的cookie,创建了一个类似2|10的链。

这实际上不起作用。。我不知道如何在查询中传递这两个组。我应该通过昏迷把他们分开吗?比如文件。组=2.10?

还是别的什么?要传递2个参数?

c#数据库检索信息

基线结构

我没有你的整个结构,所以我创建了以下简化版本:

CREATE TABLE [dbo].[Files]
(
  [ID] INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
  [Name] NVARCHAR(64) NOT NULL,
  [Group] INT NOT NULL -- Probably have a non-unique index over this.
);
GO
INSERT INTO [dbo].[Files] ([Name], [Group]) VALUES (N'My File 1', 1);
INSERT INTO [dbo].[Files] ([Name], [Group]) VALUES (N'My File 2', 2);
INSERT INTO [dbo].[Files] ([Name], [Group]) VALUES (N'My File 3', 3);
INSERT INTO [dbo].[Files] ([Name], [Group]) VALUES (N'My File 4', 2);
INSERT INTO [dbo].[Files] ([Name], [Group]) VALUES (N'My File 5', 3);
INSERT INTO [dbo].[Files] ([Name], [Group]) VALUES (N'My File 6', 5);

温度表

您可以将拆分的值插入到临时表中,并对其使用WHERE EXISTS,这可能会产生不错的性能。

-- This would be passed in from C#.
DECLARE @GroupsParam NVARCHAR(64) = N'2|3';
-- This is your SQL command, possibly a SPROC.
DECLARE @GroupsXML XML = N'<split><s>' + REPLACE(@GroupsParam, N'|', N'</s><s>') + '</s></split>';
-- Create an in-memory temp table to hold the temp data.
DECLARE @Groups TABLE
(
    [ID] INT PRIMARY KEY
);
-- Insert the records into the temp table.
INSERT INTO @Groups ([ID])
    SELECT x.value('.', 'INT')
    FROM @GroupsXML.nodes('/split/s') as records(x);
-- Use a WHERE EXISTS; which should have extremely good performance.
SELECT [F].[Name], [F].[Group] FROM [dbo].[Files] AS [F]
    WHERE EXISTS (SELECT 1 FROM @Groups AS [G] WHERE [G].[ID] = [F].[Group]);

表值参数(仅限SQL 2008+)

SQL 2008有一个巧妙的功能,您可以将表作为参数发送到数据库。很明显,只有在正确使用SqlCommands(执行参数化SQL语句)的情况下,这才会起作用,而不像您的示例(将用户创建的值附加到SQL字符串中是非常糟糕的做法-学习如何使用参数),因为您需要传入DataTable,而这是使用简单字符串值无法做到的。

为了使用它,您首先需要创建值类型:

CREATE TYPE [dbo].[IntList] AS TABLE
    ([Value] INT);
GO

接下来,我们将正确地执行操作并使用存储过程,因为这是一个静态查询,并且使用存储过程(查询计划缓存)会对性能产生一些影响。

CREATE PROCEDURE [dbo].[GetFiles]
    @Groups [dbo].[IntList] READONLY
AS BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;
    SELECT [F].[Name], [F].[Group] FROM [dbo].[Files] AS [F]
        WHERE EXISTS (SELECT 1 FROM @Groups AS [G] WHERE [G].[Value] = [F].[Group]);
END
GO

接下来,我们需要从C#开始,这是非常直接的,因为我们可以创建一个表来进行调用。

public static void GetFilesByGroups(string groupsQuery)
{
    GetFilesByGroups(groupsQuery.Split('|').Select(x => int.Parse(x)));
}
public static void GetFilesByGroups(params int[] groups)
{
    GetFilesByGroups((IEnumerable<int>)groups);
}
public static void GetFilesByGroups(IEnumerable<int> groups)
{
    // Create the DataTable that will contain our groups values.
    var table = new DataTable();
    table.Columns.Add("Value", typeof(int));
    foreach (var group in groups)
        table.Rows.Add(group);
    using (var connection = CreateConnection())
    using (var command = connection.CreateCommand())
    {
        command.CommandType = CommandType.StoredProcedure;
        command.CommandText = "[dbo].[GetFiles]";
        // Add the table like any other parameter.
        command.Parameters.AddWithValue("@Groups", table);
        using (var reader = command.ExecuteReader())
        {
            // ...
        }
    }
}

请记住:表值参数仅在SQL 2008及更高版本上受支持。

编辑:我想指出,在性能方面,dknaack的答案和临时表方法之间可能存在交叉点。对于一小部分搜索组来说,他的速度可能会更快;其中对于大的搜索组集合,临时表方法可能会更快。表值参数几乎总是更快的。这一切都只是基于我对SQL查询引擎工作方式的了解的理论:临时表可能会进行合并或散列连接,而TVP则有望进行嵌套循环。我没有做任何分析(也没有得到足够的支持票来激励我这样做),所以我不能肯定。

描述

您应该使用SqlParameter来防止Sql注入。使用IN Statement传入组ID的逗号分隔列表。

样品

// value from cookie
string groups = "2,10,99";
// Build where clause and params
List<string> where = new List<string>();
List<SqlParameter> param = new List<SqlParameter>();
foreach(string group in groups.Split(','))
{
    int groupId = Int32.Parse(group);
    string paramName = string.Format("@Group{0}", groupId);
    where.Add(paramName);
    param.Add(new SqlParameter(paramName, groupId));
}
// create command
SqlConnection myConnection = new SqlConnection("My ConnectionString");
SqlCommand command = new SqlCommand("SELECT Files.Id, Files.Name, Files.Date, " +
                            "Files.Path, Files.[Group] " +
                            "FROM Files " +
                            "WHERE Files.[Group] in (" + string.Join(",", param) + ")" +
                            "ORDER BY Files.Id DESC", myConnection);
command.Parameters.AddRange(param.ToArray());

更多信息

  • MSDN-IN(Transact-SQL)
  • C#SqlParameter示例

您可能(取决于您的数据库)正在考虑使用以下内容:

IN (2, 10)

而不是CCD_ 5运算符。

请注意,使用这样的字符串串联构造SQL可能会使代码暴露在SQL注入漏洞中,而使用正确参数化的SQL查询通常是更好的做法。然而,在您的情况下,如果参数数量不确定,则在实践中更难实现。

您需要在cookie中设置Param来创建类似2,10的链。

然后,您不需要使用=,而需要像这样使用in ()

SELECT Files.Id, Files.Name, Files.Date, Files.Path, Files.[Group] FROM Files WHERE Files.[Group] in (" + param + ") ORDER BY Files.Id DESC"

另一个错误是param + "ORDER部分缺少一个空格。