【问题标题】:How to use select, max date and declare in a sql query?如何在 sql 查询中使用选择、最大日期和声明?
【发布时间】:2021-06-18 22:42:10
【问题描述】:

我正在尝试在变量中使用声明和最大值。这是下面的查询:

Declare @MAX_BUF Datetime
 
Set @OpeningStock = (
                    SELECT @MAX_BUF = MAX(end_date) FROM [IBIS].[buf_stk]
                    WHERE SUBSTRING(CONVERT(VARCHAR,end_date ,112 ),1,6)<SUBSTRING(CONVERT(VARCHAR,getdate() ,112 ),1,6);
                    
                    SELECT COUNT(1) AS Opening_Stock 
                    FROM [IBIS].[buf_stk] AS bs(NOLOCK)
                    WHERE CAST(end_date AS DATE)=@MAX_BUF
                    )

我在“=”和“(end_date)”中遇到语法错误。请让我知道这是否可以解决。

【问题讨论】:

标签: sql sql-server azure azure-sql-database


【解决方案1】:

您实际上可以在一条语句和一次表扫描中完成所有操作:

SELECT @MAX_BUF = MAX(end_date), @OpeningStock = COUNT(1)
FROM
    (SELECT TOP (1) WITH TIES
        CAST(end_date AS date) end_date
    FROM [IBIS].[buf_stk]
    WHERE end_date >= DATEADD(month, 1, getdate())
    ORDER BY CAST(end_date AS date) DESC
    ) t;

注意事项:

  • 不要使用NOLOCK,它有很多意想不到的效果,可能会导致错误的结果
  • 切换WHERE 谓词以便命中索引(如果有的话)。不要让服务器为你做代数,它不是很擅长。

【讨论】:

    【解决方案2】:

    使用两个语句。我不喜欢将日期转换为字符串以进行日期运算。您似乎想要本月之前的最大日期。所以,DATEDIFF() 提供了一种方法(如果您在end_date 上有索引,还有更有效的方法):

    Set @@MAX_BUF = (SELECT CAST(MAX(end_date) as date)
                     FROM [IBIS].[buf_stk]
                     WHERE DATEDIFF(month, end_date, getdate()) >= 1
                    );
    
    Set @OpeningStock = (SELECT COUNT(1) AS Opening_Stock 
                         FROM [IBIS].[buf_stk] bs
                         WHERE CAST(end_date AS DATE) = @MAX_BUF
                        );
    

    您也可以将其作为单个语句执行:

    select top (1)
           @max_buf = CAST(end_date as date),
           @OpeningStock = COUNT(*)
    from FROM [IBIS].[buf_stk] bs
    where end_date < dateadd(day, 1 - day(getdate()), convert(date, getdate()))
    group by CAST(end_date as date)
    order by CAST(end_date as date) desc;
    

    请注意,这也会将日期比较更改为对优化器更友好。

    【讨论】:

    • Argh 你是如何在我还在写它的时候从我的答案中复制第二部分的:-) 但是我更喜欢你的 GROUP BY 我没想到那样
    【解决方案3】:

    如果没有看到您的表和数据,我不能有信心正确地重写您的 SQL,但是我怀疑您需要做的就是“让它工作”,稍微修改为:

    SELECT @MAX_BUF = MAX(end_date) FROM [IBIS].[buf_stk]
                        WHERE SUBSTRING(CONVERT(VARCHAR,end_date ,112 ),1,6)<SUBSTRING(CONVERT(VARCHAR,getdate() ,112 ),1,6);
                        
                        SELECT @OpeningStock=COUNT(*)
                        FROM [IBIS].[buf_stk] AS bs(NOLOCK) --<< Remove this!
                        WHERE CAST(end_date AS DATE)=@MAX_BUF
    

    话虽如此,您可以将这些组合成一个查询。您将日期作为字符串进行操作是不可分割的,并且会强制优化器扫描您的表/索引。

    如果您想查找 end_date 在该月的第一天之前的行,那么只需将其作为日期进行比较(假设您的 end_date 是实际的 date 数据类型)

    where end_date &lt; DATEADD(month, DATEDIFF(month, 0, GetDate()), 0)

    并丢失nolock 提示,除非您希望数据随机不正确。

    【讨论】:

      猜你喜欢
      • 2018-03-20
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 2017-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多