And*_*y K 3 ms-access sql-server
我对 msaccess 有以下查询
SELECT Trim([T13_RefSupplier_France_List].[Supplier_code]) AS Supplier_code,
Trim([T13_RefSupplier_France_List].[Art]) AS Internal_reference,
Trim([fp_rcli]) AS Supplier_reference,
Last(Trim([ar_fami])) AS Family_code,
Last(Trim([fp_upri])) AS Purchasing_unit,
Last(Nz([fp_pcde],0)) AS Purchasing_price,
Last(Supplier_currency_France.Recode) AS Purchasing_currency,
Last("") AS Consigned,
Last(0) AS Eco_order_qty,
Last(CDbl(Nz(Nz([fp_cond],[ar_qcdi]),0))) AS Pack_order_qty,
Last(IIf([fp_minc]=0,Nz([fp_cond],[ar_qcdi]),[fp_minc])) AS Min_order_qty,
0 AS Min_order_value,
0 AS Product_grossweight,
0 AS Product_grosscube,
Last(gpfprodu_France.fp_dela) AS Leadtime_days,
Nz([Localisation_France].[Site],"Poitiers") AS Site,
CDbl(Nz([Active],-1)) AS Supplier_active,
Max(IIf([ar1_pdanz]=0,NULL,[ar1_pdanz])) AS Ref_price
FROM ((T13_RefSupplier_France_List
LEFT JOIN ((gparticl_France
LEFT JOIN Localisation_France ON gparticl_France.ar_loco=Localisation_France.Localisation)
LEFT JOIN [*gpartic1_France] ON gparticl_France.ar_code=[*gpartic1_France].ar1_code) ON T13_RefSupplier_France_List.Art=gparticl_France.ar_code)
LEFT JOIN ((gpfprodu_France
LEFT JOIN gpfourni_France ON gpfprodu_France.fp_four=gpfourni_France.fo_code)
LEFT JOIN Supplier_currency_France ON gpfourni_France.fo_monn=Supplier_currency_France.fo_monn) ON (T13_RefSupplier_France_List.Supplier_code=gpfprodu_France.fp_four)
AND (T13_RefSupplier_France_List.Art=gpfprodu_France.fp_arti))
LEFT JOIN T13_RefSupplier_France_SupplierActive ON (T13_RefSupplier_France_List.Art=T13_RefSupplier_France_SupplierActive.Art)
AND (T13_RefSupplier_France_List.Supplier_code=T13_RefSupplier_France_SupplierActive.Supplier_code)
GROUP BY Trim([T13_RefSupplier_France_List].[Supplier_code]),
Trim([T13_RefSupplier_France_List].[Art]),
Trim([fp_rcli]),
Nz([Localisation_France].[Site],"Poitiers"),
CDbl(Nz([Active],-1))
HAVING (((Trim(T13_RefSupplier_France_List.Supplier_code))<>"FG0002")
AND ((Trim(T13_RefSupplier_France_List.Art))<>"A60101000000000"));
Run Code Online (Sandbox Code Playgroud)
我可以在GROUP BY不使用具有该LAST功能的列的情况下执行此操作,但是当我删除 LAST 函数时,我必须在GROUP BY(见下文)上添加所有列。
SELECT Trim([T13_RefSupplier_France_List].[Supplier_code]) AS Supplier_code,
Trim([T13_RefSupplier_France_List].[Art]) AS Internal_reference,
Trim([fp_rcli]) AS Supplier_reference,
Trim([ar_fami]) AS Family_code,
Trim([fp_upri]) AS Purchasing_unit,
Nz([fp_pcde],0) AS Purchasing_price,
Supplier_currency_France.Recode AS Purchasing_currency,
"" AS Consigned,
0 AS Eco_order_qty,
CDbl(Nz(Nz([fp_cond],[ar_qcdi]),0)) AS Pack_order_qty,
IIf([fp_minc]=0,Nz([fp_cond],[ar_qcdi]),[fp_minc]) AS Min_order_qty,
0 AS Min_order_value,
0 AS Product_grossweight,
0 AS Product_grosscube,
gpfprodu_France.fp_dela AS Leadtime_days,
Nz([Localisation_France].[Site],"Poitiers") AS Site,
CDbl(Nz([Active],-1)) AS Supplier_active,
Max(IIf([ar1_pdanz]=0,NULL,[ar1_pdanz])) AS Ref_price
FROM ((T13_RefSupplier_France_List
LEFT JOIN ((gparticl_France
LEFT JOIN Localisation_France ON gparticl_France.ar_loco=Localisation_France.Localisation)
LEFT JOIN [*gpartic1_France] ON gparticl_France.ar_code=[*gpartic1_France].ar1_code) ON T13_RefSupplier_France_List.Art=gparticl_France.ar_code)
LEFT JOIN ((gpfprodu_France
LEFT JOIN gpfourni_France ON gpfprodu_France.fp_four=gpfourni_France.fo_code)
LEFT JOIN Supplier_currency_France ON gpfourni_France.fo_monn=Supplier_currency_France.fo_monn) ON (T13_RefSupplier_France_List.Supplier_code=gpfprodu_France.fp_four)
AND (T13_RefSupplier_France_List.Art=gpfprodu_France.fp_arti))
LEFT JOIN T13_RefSupplier_France_SupplierActive ON (T13_RefSupplier_France_List.Art=T13_RefSupplier_France_SupplierActive.Art)
AND (T13_RefSupplier_France_List.Supplier_code=T13_RefSupplier_France_SupplierActive.Supplier_code)
GROUP BY Trim([T13_RefSupplier_France_List].[Supplier_code]),
Trim([T13_RefSupplier_France_List].[Art]),
Trim([fp_rcli]),
Nz([Localisation_France].[Site],"Poitiers"),
Trim([ar_fami]),
Trim([fp_upri]),
Nz([fp_pcde],0),
Supplier_currency_France.Recode,
"",
0,
CDbl(Nz(Nz([fp_cond],[ar_qcdi]),0)),
IIf([fp_minc]=0,Nz([fp_cond],[ar_qcdi]),[fp_minc]),
0,
0,
0,
gpfprodu_France.fp_dela,
CDbl(Nz([Active],-1))
HAVING (((Trim(T13_RefSupplier_France_List.Supplier_code))<>"FG0002")
AND ((Trim(T13_RefSupplier_France_List.Art))<>"A60101000000000"));
Run Code Online (Sandbox Code Playgroud)
问题有两方面:
LAST函数的行为是什么?LAST函数转置到 SQLServer:我该怎么办?谢谢
LAST函数的行为是什么?
从文档:
这些函数分别返回查询返回的结果集的第一条或最后一条记录中指定字段的值。如果查询不包含 ORDER BY 子句,这些函数返回的值将是任意的,因为记录通常没有特定的顺序返回。
这并不是说有关的行为,任何LAST时候一个GROUP BY子句,但是从测试看来,FIRST和LAST返回值从第一个或最后一个遇到的每个组内的行。
如果没有ORDER BY子句,由FIRST和选择的行(每组)LAST本质上是任意的。重要的一点是 multipleFIRST和LASTfunctions选择的值将来自同一行。
最后这一点意味着你不能仅仅更换FIRST或LAST通过MIN或MAX(除了不同的语义),因为最小值和最大值一般不会从同一源行是。
假设我想将该
LAST函数转置到 SQL Server:我应该怎么做?
基本上不可能完全复制这一点,因为没有精确定义访问行为;除了最简单的情况外,无法预测将选择哪一行FIRST或LAST在所有情况下选择哪一行。
也就是说,如果您可以改进查询语义以对每个组中的FIRST或LAST行进行确定性选择,那么一般的翻译是对每行进行编号(每组升序或降序),然后从编号为 1 的行中选择值。
行编号可以使用ROW_NUMBER. 在OVER子句中,GROUP BY列在PARTITION BY节中,在节中提供确定性排序ORDER BY。您将需要编写子查询或使用公用表表达式 (CTE) 将行号过滤为 1。
例如:
DECLARE @Table1 table
(
ID integer IDENTITY NOT NULL,
GroupID integer NOT NULL,
[Data] integer NOT NULL
);
INSERT @Table1
(GroupID, [Data])
VALUES
(1, 3),
(1, 2),
(1, 1),
(2, 6),
(2, 5),
(2, 4);
-- FIRST (ordered by ID ASC within GroupID)
WITH Numbered AS
(
SELECT
T.GroupID,
T.[Data],
rn = ROW_NUMBER() OVER (
PARTITION BY T.GroupID
ORDER BY T.ID ASC)
FROM @Table1 AS T
)
SELECT
N.GroupID,
N.[Data]
FROM Numbered AS N
WHERE
N.rn = 1;
-- LAST (ordered by ID DESC within GroupID)
WITH Numbered AS
(
SELECT
T.GroupID,
T.[Data],
rn = ROW_NUMBER() OVER (
PARTITION BY T.GroupID
ORDER BY T.ID DESC)
FROM @Table1 AS T
)
SELECT
N.GroupID,
N.[Data]
FROM Numbered AS N
WHERE
N.rn = 1;
Run Code Online (Sandbox Code Playgroud)
演示: db<>fiddle
在SQL Server 2012或更高版本中,这也可以使用FIRST_VALUE和LAST_VALUE窗口函数来完成,但执行计划可能效率较低。此外,这些窗口函数不是聚合,因此您需要编写表达式,使其为每个组的每一行返回相同的值,然后应用任意聚合。例如(仅针对多样性使用非确定性排序):
DECLARE @Table1 table
(
ID integer IDENTITY NOT NULL,
GroupID integer NOT NULL,
[Data] integer NOT NULL
);
INSERT @Table1
(GroupID, [Data])
VALUES
(1, 3),
(1, 2),
(1, 1),
(2, 6),
(2, 5),
(2, 4);
WITH Windowed AS
(
SELECT
T.GroupID,
fv = FIRST_VALUE(T.[Data]) OVER (
PARTITION BY T.GroupID
ORDER BY T.GroupID
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING)
FROM @Table1 AS T
)
SELECT
W.GroupID,
[Data] = MIN(W.fv) -- arbitrary aggregate
FROM Windowed AS W
GROUP BY
W.GroupID;
WITH Windowed AS
(
SELECT
T.GroupID,
lv = LAST_VALUE(T.[Data]) OVER (
PARTITION BY T.GroupID
ORDER BY T.GroupID
ROWS BETWEEN UNBOUNDED PRECEDING
AND UNBOUNDED FOLLOWING)
FROM @Table1 AS T
)
SELECT
W.GroupID,
[Data] = MAX(W.lv) -- arbitrary aggregate
FROM Windowed AS W
GROUP BY
W.GroupID;
Run Code Online (Sandbox Code Playgroud)
演示: db<>fiddle
您的第三个选择是编写 SQLCLR 用户定义聚合 (UDA)。目前无法用这些来保证确定性排序,但实现可能更接近于 Access 所做的。您需要注意所有 UDA 结果都是由同一个运算符计算的,以确保多个 UDA 调用的结果都来自同一源行。
| 归档时间: |
|
| 查看次数: |
102 次 |
| 最近记录: |