c#数据库检索信息

时间:2012-02-13 10:40:17

标签: c# sql database

我想知道一些事情。

我尝试检索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。

这实际上不起作用..而且我不知道如何在两个组中传递查询。我应该昏迷吗?比如Files.Group = 2,10?

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

4 个答案:

答案 0 :(得分:5)

基线结构

我没有完整的结构,因此我创建了以下简化版本:

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有一个neat feature,您可以将表作为参数发送到数据库。显然,这只有using SqlCommands correctly(执行参数化SQL语句)才有效,与您的示例不同(将用户创建的值附加到SQL字符串 错误练习 - 学习如何使用参数) - 因为你需要传递DataTable,你可以用一个简单的字符串值。

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

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

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

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's answer与临时表方法之间的性能可能存在交叉点。对于一小组搜索组,他的意志可能会更快;对于大量搜索组,临时表方法可能会更快。表值参数几乎总是更快。这只是基于我对SQL查询引擎如何工作的了解的理论:临时表可能会进行合并或散列连接,TVP可能希望进行嵌套循环。我还没有完成任何剖析(并没有得到足够的支持以激励我这样做)所以我无法肯定地说。

答案 1 :(得分:3)

描述

您应该使用SqlParameter来阻止Sql注入。使用IN语句传入您的组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());

更多信息

答案 2 :(得分:1)

你可能(取决于你的数据库)正在使用它:

IN (2, 10)

而不是=运算符。

请注意,使用像这样的字符串连接构造SQL可能会将代码暴露给SQL injection漏洞,并且使用正确参数化的SQL查询通常是更好的做法。但是,在您的情况下,如果您有不确定数量的参数,则在实践中难以实现。

答案 3 :(得分:1)

您需要在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部分的空格。