【问题标题】:SQL Conditional Date FiltersSQL 条件日期过滤器
【发布时间】:2014-12-21 18:25:20
【问题描述】:

我有一个 SQL 存储过程,我希望根据两个控制参数 @FilterOption、@DateFilterOption 的值应用不同的过滤器。第一个确定字段是否等于、开头或包含并且工作正常。第二个用于确定日期是否等于、大于或小于并且也可以正常工作。问题是它们不能一起工作。

另外两个参数@FilterValue 和@DateFilterValue 是用于过滤的实际值。如果我对日期选项使用所有 AND 而不是 OR,那么它就不能正常工作,那么有没有更好的方法来编码 HAVING CLAUSE 中的日期选项。

谢谢 厘米

create Procedure [dbo].[SelectPagedData]
(
    @FilterValue NVARCHAR(50),
    @CurrentPage INT,
    @PageSize INT,
    @TotalRecords INT OUTPUT,
    @OrderField INT,
    @FilterOption INT,
    @DateFilterOption INT,
    @DateFilterValue DATE
)

As

--FilterOption
--0=none
--1=CustomerStartsWith,
--2=CustomerContains,
--3=CreatedByStartsWith,
--4=CreatedByContains

--@DateFilterOption
--0=none
--1=CreatedByEquals,
--2=CreatedByGreaterThan,
--3=CreatedByLessThan,
--4=ModifiedOnEquals,
--5=ModifiedOnGreaterThan,
--6=ModifiedOnLessThan

-- Turn off count return.
Set NoCount On

-- Declare variables.
Declare @FirstRec int
Declare @LastRec int

-- Initialize variables.
Set @FirstRec = (@CurrentPage - 1) * @PageSize
Set @LastRec = (@CurrentPage * @PageSize + 1)

IF @DateFilterOption = 0 
BEGIN
    SET @DateFilterValue = '1900-01-01' 
END

IF @FilterOption = 0 
BEGIN
    SET @FilterValue = 1 
END

IF @FilterOption = 1 OR @FilterOption = 3
BEGIN
    SET @FilterValue = @FilterValue + '%' 
END

IF @FilterOption = 2 OR @FilterOption = 4
BEGIN
    SET @FilterValue = '%' + @FilterValue + '%' 
END

PRINT @FilterValue

Create Table #TempTable
(
    NewQuoteID INT IDENTITY PRIMARY KEY,
    QuoteID INT,
    GUID UNIQUEIDENTIFIER,
    EquipmentID INT, 
    QuoteName NVARCHAR(50),
    AccountNumber NVARCHAR(50),
    ADName NCHAR(10),
    CreatedOn DATETIME,
    LastModifiedOn DATETIME,
    CustomerName NVARCHAR(100),
    EquipmentName NVARCHAR(200),
    Total DECIMAL(18,2)
)

--Fill the temp table
Insert INTO #TempTable 
(
    QuoteID,
    GUID,
    EquipmentID,
    QuoteName,
    AccountNumber,
    ADName,
    CreatedOn,
    LastModifiedOn,
    CustomerName,
    EquipmentName,
    Total
)
SELECT Q.QuoteID, Q.GUID, Q.EquipmentID, Q.QuoteName, Q.AccountNumber, Q.ADName, Q.CreatedOn, 
  Q.LastModifiedOn, C.CustomerName, E.EquipmentName, SUM(QD.Amount) Total
FROM 
    Quotes Q
JOIN
    Customers C
ON Q.AccountNumber = C.AccountNumber
JOIN
    Equipment E
ON E.EquipmentID = Q.EquipmentID
JOIN
    QuoteDetails QD
ON QD.GUID = Q.GUID
GROUP BY q.QuoteID, Q.GUID, Q.EquipmentID, Q.QuoteName, Q.AccountNumber, Q.ADName,
 Q.LastModifiedOn, Q.CreatedOn,C.CustomerName, E.EquipmentName
HAVING
    (CASE @FilterOption 
    WHEN 0 THEN '1'
    WHEN 1 THEN C.CustomerName 
    WHEN 2 THEN C.CustomerName 
    WHEN 3 THEN Q.ADName 
    WHEN 4 THEN Q.ADName 
    END) LIKE @FilterValue 
 AND
(@DateFilterOption = 0 AND CONVERT(date, Q.CreatedOn,101) > @DateFilterValue)  
OR
(@DateFilterOption = 1 AND CONVERT(date, Q.CreatedOn,101) = @DateFilterValue)  
OR
 (@DateFilterOption = 2 AND CONVERT(date, Q.CreatedOn,101) > @DateFilterValue)  
OR
 (@DateFilterOption = 3 AND CONVERT(date, Q.CreatedOn,101) < @DateFilterValue)  
OR
(@DateFilterOption = 4 AND CONVERT(date, Q.LastModifiedOn,101) = @DateFilterValue)  
OR
(@DateFilterOption = 5 AND CONVERT(date, Q.LastModifiedOn,101) > @DateFilterValue)  
OR
(@DateFilterOption = 6 AND CONVERT(date, Q.LastModifiedOn,101) < @DateFilterValue)  
ORDER BY
    CASE WHEN @OrderField = 0 THEN [QuoteName] END,
    CASE WHEN @OrderField = 1 THEN [QuoteName] END DESC,
    CASE WHEN @OrderField = 2 THEN CreatedOn END,
    CASE WHEN @OrderField = 3 THEN CreatedOn END DESC,
    CASE WHEN @OrderField = 4 THEN LastModifiedOn END,
    CASE WHEN @OrderField = 5 THEN LastModifiedOn END DESC,
    CASE WHEN @OrderField = 6 THEN CustomerName END,
    CASE WHEN @OrderField = 7 THEN CustomerName END DESC,
    CASE WHEN @OrderField = 8 THEN ADName END,
    CASE WHEN @OrderField = 9 THEN ADName END DESC

--Select one page of data based on the record numbers above
Select 
    QuoteID,
    GUID,
    EquipmentID,
    QuoteName,
    AccountNumber,
    ADName,
    CreatedOn,
    LastModifiedOn,
    CustomerName,
    EquipmentName,
    Total
From 
    #TempTable
Where 
    NewQuoteID > @FirstRec 
And 
    NewQuoteID < @LastRec
ORDER BY 
    CASE WHEN @OrderField = 0 THEN [QuoteName] END,
    CASE WHEN @OrderField = 1 THEN [QuoteName] END DESC,
    CASE WHEN @OrderField = 2 THEN CreatedOn END,
    CASE WHEN @OrderField = 3 THEN CreatedOn END DESC,
    CASE WHEN @OrderField = 4 THEN LastModifiedOn END,
    CASE WHEN @OrderField = 5 THEN LastModifiedOn END DESC,
    CASE WHEN @OrderField = 6 THEN CustomerName END,
    CASE WHEN @OrderField = 7 THEN CustomerName END DESC,
    CASE WHEN @OrderField = 8 THEN ADName END,
    CASE WHEN @OrderField = 9 THEN ADName END DESC

SELECT 
    @TotalRecords = COUNT(*)
FROM 
   #TempTable

【问题讨论】:

  • 您能否详细说明您的问题?似乎有很大的混乱,我的意思是你的问题不清楚
  • 您好,如果不清楚,抱歉,我在使用日期代码时遇到问题:(@DateFilterOption = 1 AND CONVERT(date, Q.CreatedOn,101) = @DateFilterValue)。例如,如果我搜索以“T”开头并在特定日期创建的客户名称,我会得到返回正确日期的记录,但也会得到以其他字母开头的客户。如果我将 OR 更改为 AND,则不会返回任何记录

标签: sql stored-procedures parameters conditional


【解决方案1】:

我认为问题只是你的括号。尝试将having 子句更改为:

HAVING (CASE @FilterOption 
            WHEN 0 THEN '1'
            WHEN 1 THEN C.CustomerName 
            WHEN 2 THEN C.CustomerName 
            WHEN 3 THEN Q.ADName 
            WHEN 4 THEN Q.ADName 
        END) LIKE @FilterValue AND
       ((@DateFilterOption = 0 AND CONVERT(date, Q.CreatedOn,101) > @DateFilterValue) OR
        (@DateFilterOption = 1 AND CONVERT(date, Q.CreatedOn,101) = @DateFilterValue) OR
        (@DateFilterOption = 2 AND CONVERT(date, Q.CreatedOn,101) > @DateFilterValue) OR
        (@DateFilterOption = 3 AND CONVERT(date, Q.CreatedOn,101) < @DateFilterValue) OR
        (@DateFilterOption = 4 AND CONVERT(date, Q.LastModifiedOn,101) = @DateFilterValue) OR
        (@DateFilterOption = 5 AND CONVERT(date, Q.LastModifiedOn,101) > @DateFilterValue) OR
        (@DateFilterOption = 6 AND CONVERT(date, Q.LastModifiedOn,101) < @DateFilterValue)
       ) 

另外两个 cmets。首先,在where 子句中进行过滤通常更有效,因为它减少了聚合所需的数据量。其次,您不需要转换存储为日期的日期值。而且,将日期存储为字符串是一个坏主意。所以,各种日期应该已经是日期了。如果它们是datetime,而您只想将它​​们转换为date,请删除convert() 的第三个参数。用于将字符串转换为日期。 (实际上,在这种情况下,我总是使用cast(col as date),但cast()convert() 都可以。)

【讨论】:

  • 非常感谢,这正是我想要的。关于您的 cmets,数据库具有日期时间字段,因为我想在 UI 中显示此详细信息。但我只想按日期搜索,所以最好的方法是使用 cast(Q.CreatedOn as date) 而不是使用转换?
  • @CodeMechanic 。 . .正如我试图解释的那样,cast()convert()(没有第三个参数)是等价的。您应该从convert() 中删除101 参数。有了这个参数,我不确定 SQL Server 做了什么,但它可能会将列转换为字符串,然后再将其转换回日期格式。
  • 谢谢戈登,非常感谢,CM
猜你喜欢
  • 1970-01-01
  • 2013-04-17
  • 2017-06-13
  • 1970-01-01
  • 2019-01-14
  • 2021-12-25
  • 1970-01-01
  • 2021-08-15
  • 2015-11-05
相关资源
最近更新 更多