hap*_*p76 0 sql-server insert group-by json
我将 JSON 字符串传递给存储过程以插入仓库库存。
有时,会有多个具有相同产品的订单项,在相同的货架上、相同的托盘 (LPN) 上、具有相同的日期。我想将它们汇总到表中的一行中。
JSON 表示已接收并存放到某个位置的各个行。这里有 2 个相同的项目:
[{"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"}]
Run Code Online (Sandbox Code Playgroud)
所以:
ABC | 200 | 2022-01-21 00:00:00.000 | LPN1234
ABC | 400 | 2022-01-21 00:00:00.000 | LPN1234
Run Code Online (Sandbox Code Playgroud)
应汇总为:
ABC | 600 | 2022-01-21 00:00:00.000 | LPN1234
Run Code Online (Sandbox Code Playgroud)
我尝试对数量进行 GROUP BY 和 SUM,但表中的结果行仍然是 2 个单独的行。我意识到由于时间戳的原因 PutDate 不一样,所以我认为肯定将其转换为 DATE 可以解决这个问题,但事实并非如此。
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
Run Code Online (Sandbox Code Playgroud)
结果见表:
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
Run Code Online (Sandbox Code Playgroud)
巧合的是,您的查询甚至有效。
通常,您不能在查询子句中使用别名GROUP BY——您必须使用实际的列名。例如,如果您尝试运行这个简单的查询,那么Invalid column name 'ObjectName'当您尝试执行该查询时,您将收到错误(请注意,它将成功解析,但仅在执行时出错):
SELECT ObjectName = OBJECT_NAME(object_id),
NumberColumns = COUNT(*)
FROM sys.columns
GROUP BY ObjectName;
Run Code Online (Sandbox Code Playgroud)
要解决此问题,您可以使用非别名列名,或者添加 CTE 或子查询来强制抽象层并使其使查询引擎能够理解别名。
在您的查询中,您巧合地对选择中的切碎列OPENJSON...WITH和计算别名使用相同的名称。这掩盖了真正的问题。如果您更改用于从 JSON 分解中得出的名称以及 中的引用SELECT,但继续使用 中的别名GROUP BY,您将收到一条Invalid column错误消息:
SELECT Bin, StockCode, Sum(Qty) as Qty, CAST(PutDateText 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',
PutDateText VARCHAR(20) '$.PutDate', --changed this (and reference above)
LPN VARCHAR(50) '$.LPN'
)
WHERE Bin <> 'DEFAULT'
GROUP BY StockCode, Bin, PutDate, LPN;
Run Code Online (Sandbox Code Playgroud)
顺便说一句,现在我们已经更改了一些标签,我们可以看到原始查询的功能等效项实际上是这样的:
SELECT Bin, StockCode, Sum(Qty) as Qty, CAST(PutDateText 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',
PutDateText VARCHAR(20) '$.PutDate',
LPN VARCHAR(50) '$.LPN'
)
WHERE Bin <> 'DEFAULT'
GROUP BY StockCode, Bin, PutDateText, LPN;
Run Code Online (Sandbox Code Playgroud)
完成这项工作的“快速”方法不是使用别名,而只是使用直接列名称(在本例中,是使用以下函数的公式CAST():
SELECT Bin, StockCode, Sum(Qty) as Qty, CAST(PutDateText 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',
PutDateText VARCHAR(20) '$.PutDate',
LPN VARCHAR(50) '$.LPN'
)
WHERE Bin <> 'DEFAULT'
GROUP BY StockCode, Bin, CAST(PutDateText AS DATE), LPN
Run Code Online (Sandbox Code Playgroud)
就个人而言,我会使用 CTE 将 JSON 分解为表格格式,然后使用 CTE 构建查询来进行聚合。这对我来说有点“干净”,并且允许我在任何我想要的地方使用别名。这样做的优点是不必重复函数调用并使它们在SELECT&之间保持完美一致GROUP BY:
WITH JsonTable AS (
SELECT Bin, StockCode, Qty, CAST(PutDate AS DATE) as PutDate, 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'
)
)
INSERT INTO warehouse (Bin, StockCode, Qty, PutDate, VerDate, LPN)
SELECT Bin,
StockCode,
SUM(Qty) as Qty,
PutDate,
GETDATE() AS VerDate,
LPN
FROM JsonTable
WHERE Bin <> 'DEFAULT'
GROUP BY StockCode, Bin, PutDate, LPN;
Run Code Online (Sandbox Code Playgroud)
但您也可以以大致相同的方式使用内联子查询。
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 (
SELECT Bin, StockCode, Qty, CAST(PutDate AS DATE) as PutDate, 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'
)
) AS x
WHERE Bin <> 'DEFAULT'
GROUP BY StockCode, Bin, PutDate, LPN;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
931 次 |
| 最近记录: |