sql - 使用 last_value+over 的大型 sql 表

标签 sql sql-server database

首先,我不是 DBA,这篇文章包含一些难看 的 sql 代码。 :)

上下文

我有一个表,代表我所有的产品库存事件(在 SQL“TP_MOVI”中),从流程开始到结束。在这一行之后,一个产品(在 SQL“CODIGO”中)可能在多个地方(在 SQL“ARMAZEM”中)有余额。

在表中,我有所有类型的事件,我的工作是对其进行汇总,例如,直到当前日期或参数化日期为止所有产品的余额。我的逻辑是通过使用子句 LAST_VALUE() OVER() 获取所有产品+地点的最后记录),生成所有地点的余额。

我的表目前有超过 1,000,000 条记录,现在,当我尝试从该表中检索数据时,它会造成一些中断,当然,还会延迟检索数据。 我很确定是我的 SQL 代码不正确导致了这个问题,你们能帮我改进这段代码吗?

我一直在阅读关于声明WITH NO LOCK 的内容,它有帮助吗?

内容 - SQL 代码

CREATE TABLE [MOVIMENTACOES](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [DATA] [datetime] NULL,
    [CODIGO] [varchar](20) NULL,
    [ARMAZEM] [int] NULL,
    [TP_MOVI] [varchar](10),
    [QUANTIDADE] [float] NULL,
    [SALDO] [float] NULL,
    [ATV] [bit] NULL)

INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',18,'PROD',0,10,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',18,'PROD',10,15,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','456789',19,'PROD',0,20,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','456789',19,'PROD',20,15,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',28,'PROD',0,6,1)
INSERT INTO [MOVIMENTACOES]([DATA],[CODIGO],[ARMAZEM],[TP_MOVI],[QUANTIDADE],[SALDO],[ATV])VALUES('2017-04-24 05:54:59.340','123456',28,'SALE',6,-6,1)

SELECT 
    MOV.ID,
    MOV.DATA, MOV.CODIGO, MOV.ARMAZEM, MOV.TP_MOVI,
    MOV.SALDO,
    MOV.QUANTIDADE,
    MOV.SALDO + LAST_VALUE(MOV.QUANTIDADE) OVER(ORDER BY MOV.DATA ROWS UNBOUNDED PRECEDING) AS SALDO_ACUMULADO
FROM MOVIMENTACOES MOV

    LEFT OUTER JOIN MOVIMENTACOES MOV2 ON
        MOV2.CODIGO = MOV.CODIGO AND        
        MOV2.ARMAZEM = MOV.ARMAZEM AND
        MOV2.ID > MOV.ID
        AND MOV2.DATA <= '2017-04-25 07:00:00'
WHERE
    MOV2.ID IS NULL
    AND MOV.DATA <= '2017-04-25 07:00:00'

这里是模式和一些数据示例:http://rextester.com/XIXCB97220

最佳答案

根据您的评论和预期结果,您似乎只需要每个 (CODIGO,ARMAZEM) 组合的最新行(= 具有最高 ID 的行)。而您的 SALDO_ACUMULADO 计算与 SALDO + QUANTIDADE 完全相同。这转化为一个简单的 ROW_NUMBER:

WITH cte AS
 (
   SELECT 
      MOV.ID,
      MOV.DATA, MOV.CODIGO, MOV.ARMAZEM, MOV.TP_MOVI,
      MOV.SALDO,
      MOV.QUANTIDADE,
      MOV.SALDO + MOV.QUANTIDADE AS SALDO_ACUMULADO,
      ROW_NUMBER() OVER(PARTITION BY CODIGO, ARMAZEM ORDER BY MOV.ID DESC) AS rn
    FROM MOVIMENTACOES MOV
    WHERE DATA <= '2017-04-25 07:00:00'
 )
SELECT *
FROM cte
WHERE rn = 1

关于sql - 使用 last_value+over 的大型 sql 表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43611463/

相关文章:

javascript - “产品”已定义但从未在 react 中使用?

sql - DB (SQL) 自动压力/负载工具?

sql - 如何使用 PHPUnit 使用 SQL 文件设置和拆除数据库?

sql - 查看列是否有 varchar 20

sql - 管理 SQL 中的层次结构 : MPTT/nested sets vs adjacency lists vs storing paths

sql - 只要事务尚未提交,SQL Server 是否允许事务中出现约束违规?

java - 使用 Spring 的 SQL 服务器连接问题

用于计算一行中某个值出现次数的 SQL 查询

php - mysql 命令未使用 php 执行

sql-server - SQL - 一次插入和更新多条记录