4

我必须使用用户在网页上选择的值创建一个字符串,

假设我需要显示具有不同搜索条件的多台机器的文件......

我目前使用此代码:

DataTable dt = new DataTable();
SqlConnection connection = new SqlConnection();
connection.ConnectionString = ConfigurationManager
               .ConnectionStrings["DBConnectionString"].ConnectionString;
connection.Open();
SqlCommand sqlCmd = new SqlCommand
  ("SELECT FileID FROM Files
    WHERE MachineID=@machineID and date= @date", connection);
SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCmd);

sqlCmd.Parameters.AddWithValue("@machineID", machineID);
sqlCmd.Parameters.AddWithValue("@date", date);

sqlDa.Fill(dt);

现在这是一个固定查询,用户只有一台机器并且只选择一个日期......

我想做一个查询,如果他/她想要根据他/她选择的内容,用户有多个搜索选项,例如类型或大小。

此外,如果他/她可以选择多台机器......

SELECT FileID FROM Files
WHERE (MachineID=@machineID1 or MachineID = @machineID2...)
AND (date= @date and size=@size and type=@type... )

所有这些都发生在运行时......否则我必须创建一个for循环来将多台机器一个接一个地放置......并根据用户选择的情况进行多个查询......

这很有趣,我可以使用一些帮助......

4

6 回答 6

2

您可以使用WHERE MachineID IN ('Machine1', 'Machine2', 'Machine3', ... 'MachineN')

然后在您的循环中,您只需添加 1..n 台机器。IN 子句适用于 1 个元素或 n 个元素,所以应该没问题。

但是,我会考虑使用存储过程来执行此操作,而不是将 SQL 硬编码到您的应用程序中。

于 2010-04-16T21:58:37.313 回答
2

构建一个真实的表并将机器 ID 加载到其中。

那么你的 SQL 将是:

where MachineID in ( select MachineID from userMachine where userID = x)

完成后,删除用户 ID 的所有行:

delete from userMachine where userID = x.
于 2010-04-16T22:03:56.940 回答
2

如果要通过动态 SQL 执行此操作,则需要构建对 IN 函数的调用。(例如 In(id1, id2, id3...)

private string GetSql( IList<int> machineIds )
{
    var sql = new StringBuilder( "SELECT FileID FROM Files Where MachineID In(" );
    for( var i = 0; i < machineIds.Count; i++ )
    {
        if ( i > 0 )
            sql.Append(", ")
        sql.Append("@MachineId{0}", i);
    }

    sql.Append(" ) ");

    //additional parameters to query
    sql.AppendLine(" And Col1 = @Col1" );
    sql.AppendLine(" And Col2 = @Col2 ");
    ...

    return sql.ToString();
}

private DataTable GetData( IList<int> machineIds, string col1, int col2... )
{
    var dt = new DataTable();
    var sql = GetSql( machineIds );
    using ( var conn = new SqlConnection() )
    {
        conn.ConnectionString = ConfigurationManager.ConnectionStrings["DBConnectionString"].ConnectionString;
        using ( var cmd = new SqlCommand( sql, conn ) )
        {
            conn.Open();

            for( var i = 0; i < machineIds.Count; i++ )
            {
                var parameterName = string.Format("@MachineId{0}", i );
                cmd.Parameters.AddWithValue( parameterName, machineIds[i] );
            }

            cmd.Parameters.AddWithValue( "@Col1", col1 ); 
            cmd.Parameters.AddWithValue( "@Col2", col2 ); 
            ...

            using ( var da = new SqlDataAdapter( cmd ) )
            {
                da.Fill( dt );
            }
        }
    }

    return dt;
}
于 2010-04-16T22:06:39.230 回答
1

理想情况下,您试图找到一个类似于动态创建“MachineID in (1, 2, 3, 4)”的解决方案。

选项1

有很多方法可以完成此任务,将逗号分隔的字符串传递到存储过程中并动态构建 sql 字符串,然后调用“EXEC sp_executesql @sql” WHERE IN(ID 数组)

选项 2

您可以传入一串逗号分隔值,然后将这些值解析到它们自己的临时表中,然后加入它 http://vyaskn.tripod.com/passing_arrays_to_stored_procedures.htm

选项 3 - 我的选择

您现在可以使用 XML 传入值数组,然后轻松选择数组项。 http://support.microsoft.com/kb/555266

.

于 2010-04-16T22:03:04.803 回答
1

我还建议使用存储过程,否则您将面临 SQL 注入攻击——尤其是在您基于用户输入构建字符串的情况下。

就像是:

a' or 1=1; -- Do bad things

where您可以在 SQL 中使用 sp_executesql 来运行由@dcp 建议的子句构建的 SQL 语句,尽管它不会很好地优化,但它可能是一个快速运行的命令。

SQL 注入攻击示例

实现此目的的一种方法是使用 charindex。此示例演示了在传递以空格分隔的 id 列表时如何运行存储过程:

declare @machine table (machineId int, machineName varchar(20))
declare @files table (fileId int, machineId int)

insert into @machine (machineId, machineName) values (1, 'machine')
insert into @machine (machineId, machineName) values (2, 'machine 2.0')
insert into @machine (machineId, machineName) values (3, 'third machine')
insert into @machine (machineId, machineName) values (4, 'machine goes forth')
insert into @machine (machineId, machineName) values (5, 'machine V')

insert into @files (fileId, machineId) values (1, 3)
insert into @files (fileId, machineId) values (2, 3)
insert into @files (fileId, machineId) values (3, 2)
insert into @files (fileId, machineId) values (4, 1)
insert into @files (fileId, machineId) values (5, 3)
insert into @files (fileId, machineId) values (6, 5)

declare @machineText1 varchar(100)
declare @machineText2 varchar(100)
declare @machineText3 varchar(100)

set @machineText1 = '1 3 4'
set @machineText2 = '1'
set @machineText3 = '5 6'

select * from @files where charindex(rtrim(machineId), @machineText1, 1) > 0
-- returns files 1, 2, 4 and 5

select * from @files where charindex(rtrim(machineId), @machineText2, 1) > 0
-- returns file 4

select * from @files where charindex(rtrim(machineId), @machineText3, 1) > 0
--returns file 6

所以你可以创建这个存储过程来实现你的目标:

create procedure FilesForMachines (@machineIds varchar(1000))
as
select * from [Files] where charindex(rtrim(machineId), @machineIds, 1) > 0

charindex 提示来自BugSplat

于 2010-04-16T22:09:25.360 回答
1

通常,当我想创建“搜索”类型的查询时,我使用可选参数。这使我可以向参数发送某些内容或不发送任何内容,从而使查询从模糊变为非常具体。

例子:

SELECT
  COL1,
  COL2,
  COL3
FROM TABLE
WHERE (@COL1 IS NULL OR @COL1 = '' OR @COL1 = COL1)

正如您在上面所注意到的,如果您传入 NULL 或 BLANK,它不会将参数添加到查询中。如果您确实输入了一个值,那么它将用于比较。

于 2010-04-16T23:32:08.713 回答