Estou passando uma string JSON para um procedimento armazenado para inserir o inventário do armazém.
Às vezes, haverá vários itens de linha com o mesmo produto, indo para a mesma prateleira, no mesmo palete (LPN), com a mesma data. Gostaria de agregá-los em uma linha na tabela.
O JSON representa linhas individuais que foram recebidas e guardadas em um local. Aqui há 2 itens idênticos:
[{"StockCode": "ABC123", "Qty": "200", "Bin": "E4B4_L", "LPN": "1234", "PutDate": "2022-01-21 18:35:53 UTC"}, {"StockCode": "ABC123", "Qty": "400", "Bin": "E4B4_L", "LPN": "1234", "PutDate": "2022-01-21 18:36:43 UTC"}]
Então:
ABC | 200 | 2022-01-21 00:00:00.000 | LPN1234
ABC | 400 | 2022-01-21 00:00:00.000 | LPN1234
Deve agregar para:
ABC | 600 | 2022-01-21 00:00:00.000 | LPN1234
Eu tentei GROUP BY e SUM no qty, mas as linhas resultantes na tabela ainda são 2 linhas separadas. Percebi que o PutDate não era o mesmo devido ao timestamp, então pensei com certeza que lançar para DATE resolveria, mas não resolveu.
script SQL:
ALTER Procedure spc_PutAway
(@json NVARCHAR(MAX) = '')
AS
BEGIN
INSERT INTO warehouse (Bin, StockCode, Qty, PutDate, VerDate, LPN)
SELECT Bin, StockCode, Sum(Qty) as Qty, CAST(PutDate AS DATE) as PutDate, GETDATE() as VerDate, LPN
FROM OPENJSON(@json)
WITH (
Bin VARCHAR(20) '$.Bin',
StockCode VARCHAR(30) '$.StockCode',
Qty DECIMAL(18,6) '$.Qty',
PutDate VARCHAR(20) '$.PutDate',
LPN VARCHAR(50) '$.LPN'
)
WHERE Bin <> 'DEFAULT'
GROUP BY StockCode, Bin, PutDate, LPN
END
Resultados na tabela:
Bin StockCode Qty PutDate VerDate LPN TransID VerCol
E4B4_L ABC123 200.000000 2022-01-21 00:00:00.000 2022-01-21 10:52:43.823 1234 1 0x000000000000275D
E4B4_L ABC123 400.000000 2022-01-21 00:00:00.000 2022-01-21 10:52:43.823 1234 2 0x000000000000275E
É uma coincidência que sua consulta funcione.
Normalmente, você não pode usar um alias na
GROUP BY
cláusula de uma consulta - você precisa usar o nome real da coluna. Por exemplo, se você tentar executar esta consulta simples, receberá o erroInvalid column name 'ObjectName'
ao tentar executar a consulta (observe que ela será analisada com sucesso, mas apenas erro na execução):Para corrigir isso, você usaria o nome da coluna sem alias ou adicionaria um CTE ou subconsulta para forçar a camada de abstração e fazer com que o mecanismo de consulta entendesse o alias.
Em sua consulta, você usa coincidentemente o mesmo nome para a coluna fragmentada do
OPENJSON...WITH
e o alias calculado em sua seleção. Isso obscurece a questão real. Se você alterar o nome que está usando para sair da fragmentação JSON e a referência em seuSELECT
, mas continuar usando o Alias em seuGROUP BY
, receberá umaInvalid column
mensagem de erro:Como aparte, agora que alteramos alguns dos rótulos, podemos ver que o equivalente funcional da sua consulta original é, na verdade, este:
A maneira "rápida" de fazer isso funcionar não é usar o alias, e apenas usar o nome da coluna direta (neste caso, uma fórmula usando a
CAST()
função:Pessoalmente, eu usaria um CTE para fragmentar o JSON em um formato tabular e, em seguida, construir minha consulta usando o CTE para fazer as agregações. Isso parece um pouco mais "limpo" para mim e me permite usar os nomes de alias onde eu quiser. Isso tem a vantagem de não ter que repetir chamadas de função e mantê-las em perfeita harmonia entre
SELECT
&GROUP BY
:Mas você também pode usar uma subconsulta em linha da mesma maneira.