如何使用WHERE和AND查询而不组合多个字段

时间:2018-06-07 20:39:00

标签: sql-server where

我正在使用Visual Studio查询SQL数据库的表。我有参数供用户在开始日期和结束日期中选择日期,或者能够输入服务器名称。

我还想要发生的是,如果用户想要选择日期和服务器名称,我只希望该表返回具有该特定服务器名称的日期,但是发生的是它返回具有所选日期的所有行以及具有键入的服务器名称的所有行。我有2行具有相同的服务器名称,但其中一行的日期为06/06,另一行的日期为06/07。如果我选择日期06/07和服务器名称:SQL1,我只希望表返回服务器的那一行:SQL1,日期为:06/07。

SELECT        ServerName, ServiceName, Status, Date
FROM          ServicesStatus
WHERE         (Date = @Date) AND (@Date BETWEEN @StartDate AND @EndDate) OR
              (ServerName = @ServerName) OR
              (Date = @Date) AND (@Date BETWEEN @StartDate AND @EndDate) AND (ServerName = @ServerName)

当我选择06/07/18作为日期时,这是第一个WHERE语句:

ServerName:    ServiceName:         Date:
SQL3           Service1             06/07/18
SQL4           Service2             06/07/18
SQL2           Service1             06/07/18
SQL1           Service1             06/07/18

当我选择SQL1作为我的ServerName时,这是第一个OR之后的第二个WHERE语句:

ServerName:    ServiceName:         Date:
SQL1           Service1             06/07/18
SQL1           Service2             06/06/18

并且这是我的问题!当我在第二个OR之后尝试做第三个WHERE语句时它看起来像这样,因为它结合了我选择的日期(06/07/18)和我输入的服务器名称是SQL1:

ServerName:    ServiceName:         Date:
SQL3           Service1             06/07/18
SQL4           Service2             06/07/18
SQL2           Service1             06/07/18
SQL1           Service1             06/07/18
SQL1           Service2             06/06/18

如果我选择上述数据(SQL1和06/07/18),如果他们选择按服务器名称和日期过滤它,我想要这样:

ServerName:    ServiceName:         Date:
SQL1           Service1             06/07/18

我知道这是一个简单的查询,但由于某些原因我无法理解。

3 个答案:

答案 0 :(得分:0)

您需要的是动态SQL查询或准备语句!我们可以通过组合它们来动态创建优化过滤逻辑。您还可以修改以沿着相同的行引入存储过程。

动态准备语句:在具有动态过滤功能的SQL Server实例上创建该命令的准备版本。

  1. 准备好的声明没有引入SQL注入
  2. 改进的解决方案,具有以下逻辑,可动态添加参数和过滤字符串。 (WHERE子句中的所有参数都会导致表扫描,因为执行引擎会为最坏的情况做好准备)
  3. 以下示例演示了Prepare方法的用法。

    private static void SqlCommandPrepareEx(string connectionString)
    {
        var sqlParameters = new List<SqlParameter>();
        var filterSb = new StringBuilder();
    
        PopulateParameters(sqlParameters, filterSb);
    
        using (var connection = new SqlConnection(connectionString))
        {
            connection.Open();
            var command = new SqlCommand(null, connection);
    
            // Create and prepare an SQL statement.
            command.CommandText = "SELECT ServerName, ServiceName, Status, Date" + "FROM ServicesStatus" + filterSb;
    
            // Adding Parameters
            command.Parameters.AddRange(sqlParameters.ToArray());
            // Call Prepare after setting the Command text and Parameters.
            command.Prepare();
            command.ExecuteNonQuery();
        }
    }
    
    private static void PopulateParameters(List<SqlParameter> sqlParameters, StringBuilder filterSb)
    {
        if (!string.IsNullOrEmpty(InputDate))
        {
            // Add Parameter
            var sqlParameter = new SqlParameter("@date", SqlDbType.Date) { Value = InputDate };
            sqlParameters.Add(sqlParameter);
            // Add Filter
            filterSb.AppendLine(filterSb.Length > 0 ? " AND Date=@date" : " WHERE Date=@date");
        }
    
        if (!string.IsNullOrEmpty(StartDate))
        {
            // Add Parameter
            var sqlParameter = new SqlParameter("@startDate", SqlDbType.Date) { Value = StartDate };
            sqlParameters.Add(sqlParameter);
            // Add Filter
            // Using Between affects performance and don't allow indexes to be used
            filterSb.AppendLine(filterSb.Length > 0 ? " AND Date>=@startDate" : " WHERE Date>=@startDate");
        }
    
        if (!string.IsNullOrEmpty(EndDate))
        {
            // Add Parameter
            var sqlParameter = new SqlParameter("@endDate", SqlDbType.Date) { Value = EndDate };
            sqlParameters.Add(sqlParameter);
            // Add Filter
            // Using Between affects performance and don't allow indexes to be used
            filterSb.AppendLine(filterSb.Length > 0 ? " AND Date<=@endDate" : " WHERE Date<=@endDate");
        }
    
        if (!string.IsNullOrEmpty(ServerName))
        {
            // Add Parameter
            var sqlParameter = new SqlParameter("@serverName", SqlDbType.VarChar) { Value = ServerName };
            sqlParameters.Add(sqlParameter);
            // Add Filter
            filterSb.AppendLine(filterSb.Length > 0 ? " AND ServerName=@serverName" : " WHERE ServerName=@serverName");
        }
    }
    

    单独了解动态查询: 以下示例了解动态查询,通过在具有适当逻辑的存储过程中引入它可以使其更安全。

    var filterString = string.Empty;
    string dynamicQuery = @"
    SELECT        ServerName, ServiceName, Status, Date
    FROM          ServicesStatus
    {0}";
    
    //Populate Filter String
    var filterSb = new StringBuilder();
    
    if(string.IsNullOrEmpty(dateFilter)){
        filterSb.AppendLine("Date = {0}", dateFilter)
    }
    
    // use similar code for other filters
    
    if(filterSb.Length > 0){
        filterString = string.Format(" WHERE {0}", filterSb);
    }
    
    // Append filter
    string.Format(dynamicQuery, filterString);
    

    仅了解准备好的声明: 在SQL Server实例上创建命令的准备版本。

    private static void SqlCommandPrepareEx(string connectionString)
    {
        using (SqlConnection connection = new SqlConnection(connectionString))
        {
            connection.Open();
            SqlCommand command = new SqlCommand(null, connection);
    
            // Create and prepare an SQL statement.
            command.CommandText =
                "INSERT INTO Region (RegionID, RegionDescription) " +
                "VALUES (@id, @desc)";
            SqlParameter idParam = new SqlParameter("@id", SqlDbType.Int, 0);
            SqlParameter descParam = 
                new SqlParameter("@desc", SqlDbType.Text, 100);
            idParam.Value = 20;
            descParam.Value = "First Region";
            command.Parameters.Add(idParam);
            command.Parameters.Add(descParam);
    
            // Call Prepare after setting the Commandtext and Parameters.
            command.Prepare();
            command.ExecuteNonQuery();
    
            // Change parameter values and call ExecuteNonQuery.
            command.Parameters[0].Value = 21;
            command.Parameters[1].Value = "Second Region";
            command.ExecuteNonQuery();
        }
    }
    

答案 1 :(得分:0)

如果未提供@Date和@ServerName的值为NULL,则以下内容适合您。我创建了一个示例表,并使用您提供的数据填充它。这应该产生您正在寻找的结果。如果需要,您可以调整DATEDIFF的精度。我还假设开始日期和结束日期是同一天的不同间隔,因为它没有指定。随意修改。

CREATE TABLE ServicesStatus (
id INT,
serverName VARCHAR(255),
ServiceName VARCHAR(255),
Date DATETIME2
);


DECLARE @Date DATETIME2 = '06/07/18'
DECLARE @StartDate DATETIME2 = dateadd(second, 1, dateadd(day, datediff(day, 0, @Date), 0))
    , @EndDate DATETIME2 = dateadd(second, -1, dateadd(day, datediff(day, 0, @Date)+1, 0))
    , @ServerName VARCHAR(255) = NULL

SELECT    ServerName, ServiceName, Date
FROM      ServicesStatus
WHERE     ServerName = COALESCE(@ServerName,ServerName)
AND       (@Date IS NULL OR DATEDIFF(DAY,@StartDate,Date) >= 0)
AND       (@Date IS NULL OR DATEDIFF(DAY,Date,@EndDate) <= 0)

答案 2 :(得分:0)

这样的东西会起作用。如果您没有将未知值设置为NULL,请将NULL替换为您在变量中使用的任何值,并且不要关心&#34;。

你没有为@StartDate和@EndDate提供值,所以我认为它们只是作为外部过滤器。

--The Setup
DECLARE @ServicesStatus TABLE ([ServerName] varchar(4), [ServiceName] varchar(8), [Date] datetime)
;

INSERT INTO @ServicesStatus
    ([ServerName], [ServiceName], [Date])
VALUES
    ('SQL3', 'Service1', '2018-06-07 00:00:00'),
    ('SQL4', 'Service2', '2018-06-07 00:00:00'),
    ('SQL2', 'Service1', '2018-06-07 00:00:00'),
    ('SQL1', 'Service1', '2018-06-07 00:00:00'),
    ('SQL1', 'Service2', '2018-06-06 00:00:00')
;

DECLARE @StartDate date = '20180601'
DECLARE @EndDate date = '20180610'
DECLARE @Date date = '20180607'
DECLARE @ServerName nvarchar(4)='SQL1'

--The Code
SELECT        ServerName, ServiceName, Date
FROM          @ServicesStatus
WHERE         (@Date BETWEEN @StartDate AND @EndDate OR @DATE IS NULL) AND
              (
                (ServerName = @ServerName AND @Date IS NULL) OR
                (@ServerName IS NULL AND @Date = date) OR
                (Date= @Date AND ServerName = @ServerName)
               )

使用@Servername = NULL和@Date =&#39; 20180607&#39;,你得到

ServerName  ServiceName Date
SQL3    Service1    2018-06-07 00:00:00.000
SQL4    Service2    2018-06-07 00:00:00.000
SQL2    Service1    2018-06-07 00:00:00.000
SQL1    Service1    2018-06-07 00:00:00.000

使用@Date = NULL和@ServerName =&#39; SQL1&#39;你得到了

ServerName  ServiceName Date
SQL1    Service1    2018-06-07 00:00:00.000
SQL1    Service2    2018-06-06 00:00:00.000

使用@Date =&#39; 20180607&#39;和@ServerName =&#39; SQL1&#39;,你得到

ServerName  ServiceName Date
SQL1    Service1    2018-06-07 00:00:00.000