【问题标题】:Best practice: Searching table against day, month or year最佳实践:根据日、月或年搜索表
【发布时间】:2009-11-08 19:39:21
【问题描述】:

我有一个带有“日期”列的表,其中将查询用户输入(使用存储过程)..结果将显示在数据网格上..

现在用户可以输入年、年/月、年/月/日..(从下拉列表中)

我知道有很多可能的方法来处理不同的查询.. 但是我正在尝试找出最佳实践:

解决方案 1:有 3 个不同的存储过程,每种情况一个。

解决方案 2:有 1 个存储过程,带有 1 个额外参数作为 searchlvl ,然后使用 IF ELSE 语句来决定应该应用什么 lvl 的搜索。

解决方案 3:有 1 个存储过程,并将日期时间作为 3 个不同的参数发送,然后检查 IF 参数是否为空,并使用它来决定搜索 lvl

解决方案 4:您的建议 :)

注意:我知道如何进行部分搜索(使用 datepart),我的问题是关于我提供的 3 个解决方案或答案中提供的任何其他解决方案中的最佳实践。 就像哪个会更快,数据库更轻等等.. 而且会更慢,更重..

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    没有关卡。

    当用户选择 2009 年时,您搜索日期 >= '2009.01.01 00:00' 和

    当他选择 2009 年的第 1 个月时,您搜索日期 >= '2009.01.01 00:00' 和

    当然,您不会将日期作为字符串传递,您应该使用 CONVERT() 或将日期作为 DATETIME 类型传递。这是通用的解决方案,而且速度很快,因为它将使用索引。您可以创建需要两个日期的存储过程,它将允许按每个日期范围进行搜索,而不仅仅是年/月/日。

    【讨论】:

    • +1,但是,您是否建议在 UI 层执行将三个 doprdown 转换为单个日期的逻辑?
    • 我没有在 UI 方面提出任何建议。如果他想要年/月/日下拉列表,他可以拥有它们。我建议在数据库端进行过滤。
    • +1 简单和快速(将等待更多答案)
    • 正如 pipTheGeek 所指出的,我最终需要在 UI 端进行一些额外的编码和计算(以及逻辑)..
    【解决方案2】:

    我不会做以上任何事情。

    您应该将存储过程设计为采用三种不同的整数,一种用于日,一种用于月,一种用于年。让参数可以为空,但要建立一个约定,以便只使用有意义的参数组合。然后根据参数构造一个 MINDATE 和 MAXDATE。

    根据日/年/月搜索日期时间列需要如下查询:

    SELECT * FROM table WHERE date > MINDATE AND date < MAXDATE
    

    这是相当低效的,但不是一个明确的问题。

    另一种方法(如果表很大)是创建一个带有年/月/日整数列的索引视图,并在那里搜索精确匹配。要创建这样的视图,请使用 DATEPART()。

    【讨论】:

    • 按索引日期搜索效率低下?在这个视图上创建视图和附加索引是不是太多了?
    • 也许这有点矫枉过正,但我​​猜 SQLServer 在索引日期时间列时会在底层进行类似的优化。
    • 如果是这样,它应该会使用它,那么为什么要再次使用它呢?为什么不在日期时间列上创建索引?
    • 对不起,我对那个不够清楚。如果没有进一步的研究,我会说 KISS。
    【解决方案3】:

    您可以使用 datepart 获取要过滤的日期部分

    declare @table table(
            DateVal DATETIME
    )
    
    INSERT INTO @table SELECT GETDATE()
    
    
    DECLARE @Year INT,
            @Month INT,
            @Day INT
    
    SELECT  @Year = 2009
    
    SELECT  DATEPART(YY, DateVal) DateYear,
            DATEPART(MM, DateVal) DateMonth,
            DATEPART(DD, DateVal) DateDay,
            *
    FROM @table
    WHERE   (DATEPART(YY, DateVal) = @Year OR @Year IS NULL)
    AND     (DATEPART(MM, DateVal) = @Month OR @Month IS NULL)
    AND     (DATEPART(DD, DateVal) = @Day OR @Day IS NULL)
    

    【讨论】:

    • 我会选择一个 sp,3 个参数并按照我编辑的答案中所示进行测试。
    • 是的,我的老板提出了类似的方法,没有插入等,所以+1“由于上级当局的影响”:D
    • 首先设计简单,然后当您看到性能问题时,再调查那些 X-)
    • 有了这个,你的应用程序会随着数据变大而变慢,直到竞争对手来展示他的应用程序比你的应用程序快得多...... 坏主意
    【解决方案4】:

    我会将年/月/日作为单独的参数传递到 one 存储过程中,例如默认为 NULL。

    然后,我会使用 DATEADD 来建立从/到日期时间并使用它

    ...
    SELECT
        @ToYear = ISNULL(@ToYear, DATEPART(year, GETDATE()), --or some base value, such as "1900"
        @ToMonth = ...
    
    ...
    SELECT
        @DateTo = DATEADD(year, @ToYear, DATEADD(month, @ToMonth, DATEADD(day, @ToDay, 0), 0), 0)
    ....
    SELECT * FROM myTable WHERE DateColumn >= @DateFrom AND DateColumn <= @DateTo
    

    我不会使用列上的任何函数或条件逻辑在选择之间切换

    【讨论】:

    • 我认为“ISNULL”隐含地执行 IF 逻辑..所以你的解决方案是给任何 NULL 输入一个基值,然后做一个范围检查(就像 lukeled 建议的那样).. 不会做null-> 在发送到 DB 之前更好地在 UI 端设置值?
    • 如果在数据库或客户端中无关紧要。我会说 DB,因为存储过程应该检查/清理输入。
    • 同意,我宁愿处理SP中的逻辑,客户端是否传递错误的日期,或者忘记传递日期等。特别是如果多个客户端调用相同的过程,逻辑应该集中未分发。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-25
    • 1970-01-01
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 2021-03-31
    相关资源
    最近更新 更多