【问题标题】:SQL query not returning all rowsSQL查询不返回所有行
【发布时间】:2015-02-18 16:17:15
【问题描述】:

我在 SQL Server 中有一个表,它有很多行,有一个 created_date 列。此列包含从 2006 年开始的行。

我想获取在 2015 年 2 月及之前创建的所有行。此存储过程有一个参数 @month。它应该根据输入的@month 值选择所有行。

这是我的查询:

select * 
from products 
where 1=1 
  and year(created_date) <= 2015 
  and month(created_date) <= @month 

但此查询仅返回在往年 2 月 月及之前创建的记录不包括 在 2014 年其他月份创建的记录(例如 2014- 03-17, 2014-05-05 除外)。

我必须根据输入的@month 获得一个新日期。假设我进入了 7 月,我想要条件“where created_date

所以我改变了我的查询,

declare @date datetime
set @date = CAST((2015 + '-' + @month + '-' + 28) as datetime)
select * 
from products 
where 1=1 
and year(created_date) <= 2015 

但是这个查询返回 1905-08-08 00:00:00.000 我想得到 2015-02-28 00:00:00.000 而且我必须根据输入的@month 找到总天数,这样我可以将该数字传递给 CAST((2015 + '-' + @month + '-' + 28) as datetime) 而不是 28。

【问题讨论】:

  • 只使用具有您想要的限制值的日期变量作为标准,而不是使用 year() 和 month() 函数?例如。 created_date

标签: sql-server


【解决方案1】:

只需使用单个日期并指定created_date 列必须小于该日期:

declare @newestDate datetime = '2015-03-01'

select * 
from products
where created_date < @newestDate

请注意,我将日期设置为 3 月 1 日,但在查询中我使用 &lt; 而不是 &lt;=。这将处理包含时间组件的created_date 值,例如2015-02-28 23:59:59

要生成“上一年二月”的值,您实际上可能希望使用去年的当前月份,如果是这样,您的日期将是:

declare @newestDate datetime = 
    DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE())+1, 0))

这将在下个月(即 3 月)生效,并为您的查询提供一个滚动月份。

【讨论】:

    【解决方案2】:

    尽可能将日期/时间字段与单个值进行比较——这对性能也是最好的。您可以使用DATEADDDATEDIFF“四舍五入”日期。

    DECLARE @startOfNextMonth DATETIME;
    SELECT @startOfNextMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0);
    select * from products where 1=1 and created_date < @startOfNextMonth;
    

    转换日期的字符串操作也是可能的,但往往性能更差,而且很难正确处理。如果您想“四舍五入”到年、分钟、15 秒的周期等,这种技术通常适用,这对于字符串来说要困难得多。

    如果可以,请重写您的存储过程,使其不采用@month 参数,而是采用客户计算的绝对值——它更通用,也更易于使用。然后您的查询简单地简化为

    select * from products where 1=1 and created_date < @limit;
    

    当然,如果你必须使用@month,你可以在存储过程本身中构造这个偏移量:

    DECLARE @limit DATETIME = 
        DATEFROMPARTS(DATEPART(YEAR, GETDATE()), @month, 1)
    ;
    

    这利用了DATEFROMPARTS,它是随 SQL Server 2012 引入的。对于以前的版本,可靠地构造日期相当麻烦。如果将区域设置设置为意外情况,有许多错误的方法会中断。 DATEADD 再次提供帮助:

    DECLARE @limit DATETIME = 
        DATEADD(MONTH, (DATEPART(YEAR, GETDATE()) - 1900) * 12 + @month - 1, 0)
    ;
    

    这些不是构造日期时间值的唯一方法,但字符串操作在任何情况下都很棘手(因为在区域设置下不会中断的唯一可靠格式是YYYYMMDD,没有破折号)。

    【讨论】:

      【解决方案3】:

      在这个问题中:Create a date with T-SQL 您将看到如何在给定年份和月份的情况下构造 sql-server 日期数据类型。假设您称其为“my_date”。

      然后您将能够执行以下操作:

      SELECT * FROM products WHERE created_date < my_date
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-03-29
        • 1970-01-01
        • 1970-01-01
        • 2016-01-31
        • 1970-01-01
        • 2011-07-26
        • 1970-01-01
        相关资源
        最近更新 更多