Se você já precisou fazer alguma query para agilizar o KARDEX do Protheus, hoje iremos demonstrar um exemplo de como fazer.
Esse exemplo foi criado e gentilmente disponibilizado pelo grande Bruno Cesar Mendes Jacinto ( LinkedIn ).
O primeiro passo é criar a função no SQL Server, sendo que o nome dela é KARDEX_SQL. Ela irá receber 4 parâmetros, a data da SB9, a data inicial de movimentações, a data final de movimentações e a filial.
Abaixo o código da função completa (substitua o 99 pelo seu grupo de empresas, por exemplo, SB2990 para SB2010):
USE [NOME_DA_SUA_BASE]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE OR ALTER FUNCTION [dbo].[KARDEX_SQL]
( @dtB9 char(8), @dtade char(8), @dtate char(8), @Filial char(2) )
RETURNS table
AS
RETURN (
SELECT B2_COD AS PRODUTO,
B2_LOCAL AS ARMAZEM,
B1_TIPO,
0 AS SALDO_INI,
0 AS ENTRADA_INI,
0 AS ENTRADA_FIM,
0 AS SAIDA_INI,
0 AS SAIDA_FIM,
0 AS CUSTO_INI,
0 AS CUS_ENT_INI,
0 AS CUS_ENT_FIM,
0 AS CUS_SAI_INI,
0 AS CUS_SAI_FIM
FROM SB2990 (NOLOCK) AS B2
INNER JOIN SB1990 (NOLOCK) AS B1 ON B2_COD = B1_COD
WHERE B2.D_E_L_E_T_ != '*'
AND B1.D_E_L_E_T_ != '*'
GROUP BY B2_COD, B2_LOCAL, B1_TIPO
UNION ALL
SELECT B9_COD AS PRODUTO,
B9_LOCAL AS ARMAZEM,
B1_TIPO,
SUM(B9_QINI) AS SALDO_INI,
0 AS ENTRADA_INI,
0 AS ENTRADA_FIM,
0 AS SAIDA_INI,
0 AS SAIDA_FIM,
SUM(B9_VINI1) AS CUSTO_INI,
0 AS CUS_ENT_INI,
0 AS CUS_ENT_FIM,
0 AS CUS_SAI_INI,
0 AS CUS_SAI_FIM
FROM SB9990 (NOLOCK) AS B9
INNER JOIN SB1990 (NOLOCK) AS B1 ON B9_COD = B1_COD
WHERE B9.D_E_L_E_T_ != '*'
AND B1.D_E_L_E_T_ != '*'
AND B9_DATA = @dtB9
AND B9_FILIAL = @Filial
GROUP BY B9_COD, B9_LOCAL, B1_TIPO
UNION ALL
SELECT D1_COD AS PRODUTO,
D1_LOCAL AS ARMAZEM,
B1_TIPO,
0 AS SALDO_INI,
ROUND(SUM(CASE WHEN D1_DTDIGIT BETWEEN @dtade AND @dtate-1 THEN D1_QUANT ELSE 0 END ),2) AS ENTRADA_INI,
ROUND(SUM(CASE WHEN D1_DTDIGIT BETWEEN @dtade AND @dtate THEN D1_QUANT ELSE 0 END ),2) AS ENTRADA_FIM,
0 AS SAIDA_INI,
0 AS SAIDA_FIM,
0 AS CUSTO_INI,
ROUND(SUM(CASE WHEN D1_DTDIGIT BETWEEN @dtade AND @dtate-1 THEN D1_CUSTO ELSE 0 END ),2) AS CUS_ENT_INI,
ROUND(SUM(CASE WHEN D1_DTDIGIT BETWEEN @dtade AND @dtate THEN D1_CUSTO ELSE 0 END ),2) AS CUS_ENT_FIM,
0 AS CUS_SAI_INI,
0 AS CUS_SAI_FIM
FROM SD1990 (NOLOCK) AS D1
INNER JOIN SF4990 (NOLOCK) AS F4 ON D1_TES = F4_CODIGO
INNER JOIN SB1990 (NOLOCK) AS B1 ON D1_COD = B1_COD
WHERE D1.D_E_L_E_T_ != '*'
AND B1.D_E_L_E_T_ != '*'
AND F4.D_E_L_E_T_ != '*'
AND D1_DTDIGIT BETWEEN @dtade AND @dtate
AND D1_FILIAL = @Filial
AND D1_ORIGLAN != 'LF'
AND F4.F4_TIPO = 'E'
AND F4_ESTOQUE = 'S'
GROUP BY D1_COD, D1_LOCAL, B1_TIPO
UNION ALL
SELECT D2_COD,
D2_LOCAL AS ARMAZEM,
B1_TIPO,
0 AS SALDO_INI,
0 AS ENTRADA_INI,
0 AS ENTRADA_FIM,
ROUND(SUM(CASE WHEN D2_EMISSAO BETWEEN @dtade AND @dtate-1 THEN D2_QUANT ELSE 0 END ),2) AS SAIDA_INI,
ROUND(SUM(CASE WHEN D2_EMISSAO BETWEEN @dtade AND @dtate THEN D2_QUANT ELSE 0 END ),2) AS SAIDA_FIM,
0 AS CUSTO_INI,
0 AS CUS_ENT_INI,
0 AS CUS_ENT_FIM,
ROUND(SUM(CASE WHEN D2_EMISSAO BETWEEN @dtade AND @dtate-1 THEN D2_CUSTO1 ELSE 0 END ),2) AS CUS_SAI_INI,
ROUND(SUM(CASE WHEN D2_EMISSAO BETWEEN @dtade AND @dtate THEN D2_CUSTO1 ELSE 0 END ),2) AS CUS_SAI_FIM
FROM SD2990 (NOLOCK) AS D2
INNER JOIN SF4990 (NOLOCK) AS F4 ON D2_TES = F4_CODIGO
INNER JOIN SB1990 (NOLOCK) AS B1 ON D2_COD = B1_COD
WHERE D2.D_E_L_E_T_ != '*'
AND F4.D_E_L_E_T_ != '*'
AND B1.D_E_L_E_T_ != '*'
AND D2_EMISSAO BETWEEN @dtade AND @dtate
AND F4.F4_TIPO = 'S'
AND D2.D2_ORIGLAN != 'LF'
AND D2_FILIAL = @Filial
AND F4_ESTOQUE = 'S'
GROUP BY D2_COD, D2_LOCAL, B1_TIPO
UNION ALL
SELECT D3_COD,
D3_LOCAL AS ARMAZEM,
B1_TIPO,
0 AS SALDO_INI,
ROUND(SUM(CASE WHEN D3_TM <='499' AND D3_EMISSAO BETWEEN @dtade AND @dtate-1 THEN D3_QUANT ELSE 0 END ),2) AS ENTRADA_INI,
ROUND(SUM(CASE WHEN D3_TM <='499' AND D3_EMISSAO BETWEEN @dtade AND @dtate THEN D3_QUANT ELSE 0 END ),2) AS ENTRADA_FIM,
ROUND(SUM(CASE WHEN D3_TM >'499' AND D3_EMISSAO BETWEEN @dtade AND @dtate-1 THEN D3_QUANT ELSE 0 END ),2) AS SAIDA_INI,
ROUND(SUM(CASE WHEN D3_TM >'499' AND D3_EMISSAO BETWEEN @dtade AND @dtate THEN D3_QUANT ELSE 0 END ),2) AS SAIDA_FIM,
0 AS CUSTO_INI,
ROUND(SUM(CASE WHEN D3_TM <='499' AND D3_EMISSAO BETWEEN @dtade AND @dtate-1 THEN D3_CUSTO1 ELSE 0 END ),2) AS CUS_ENT_INI,
ROUND(SUM(CASE WHEN D3_TM <='499' AND D3_EMISSAO BETWEEN @dtade AND @dtate THEN D3_CUSTO1 ELSE 0 END ),2) AS CUS_ENT_FIM,
ROUND(SUM(CASE WHEN D3_TM >'499' AND D3_EMISSAO BETWEEN @dtade AND @dtate-1 THEN D3_CUSTO1 ELSE 0 END ),2) AS CUS_SAI_INI,
ROUND(SUM(CASE WHEN D3_TM >'499' AND D3_EMISSAO BETWEEN @dtade AND @dtate THEN D3_CUSTO1 ELSE 0 END ),2) AS CUS_SAI_FIM
FROM SD3990 (NOLOCK) AS D3
INNER JOIN SB1990 (NOLOCK) AS B1 ON D3_COD = B1_COD
WHERE D3.D_E_L_E_T_ != '*'
AND B1.D_E_L_E_T_ != '*'
AND D3_ESTORNO != 'S'
AND D3_FILIAL = @Filial
AND D3_EMISSAO BETWEEN @dtade AND @dtate
GROUP BY D3_COD, D3_LOCAL, B1_TIPO
)
Como o retorno da função é uma tabela, para executar, basta dar um select no resultado dela, conforme o seguinte comando:
SELECT * FROM KARDEX_SQL('20211102', '20210101', '20211231', '01');
Abaixo um print do resultado:
Bom pessoal, por hoje é só.
Abraços e até a próxima.

Fiz uma query dessa tbm realmente agiliza muito.
Opa, obrigado pelo comentário Lucas.
Abraços.
Muito bom, vai ajudar bastante, obrigado Dan e Bruno por compartilhar!
Opa, obrigado pelo comentário jovem.
Grande abraço.
Dan muito bom o exemplo, gostei bastante, tenho alguns exemplos aqui de Cursor no SQL e gostaria de compartilhar contigo, para onde posso enviar se vc achar interessante, publique no seu site.
Opa, fala Robson, tudo joia?
Pode mandar nos links de Contato – https://terminaldeinformacao.com/contato/
Ou no cabeçalho do site, também tem o WhatsApp, ai você envia junto com seu LinkedIn ou forma de contato que nós postamos aqui o artigo.
Grande abraço e obrigado pelo interesse.
Sensacional !! ! Outro Nível de programação.
Por acaso vocês tem uma query que cruza produto final vs consumido.
Obrigado pelo comentário Francisco, o Bruno manja mesmo.
Irei verificar e se encontrar algo, lhe aviso.
Muito útil, porém alguém teria uma versão “melhorada” que traga também as movimentações de endereçamento (SDB) ?
Boa tarde Luiz.
Obrigado pelo comentário. Ainda não tem, mas se você tiver uma base para disponibilizar os testes, podemos adaptar a query.
Ou se você também quiser adaptar e depois mandar ela revisada, ai eu atualizo aqui o artigo.
Um grande abraço.