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个参数?
基线结构
我没有你的整个结构,所以我创建了以下简化版本:
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
部分缺少一个空格。