Select 列合计没有分组依据
Select columns without group by in aggregate
我正在使用 SQL Server 2014。我的结构如下:
Id BIGINT,
ItemName NVARCHAR(4000),
RecordDate DATETIME2,
Supplier NVARCHAR(450),
Quantity DECIMAL(18, 2),
ItemUnit NVARCHAR(2000),
EntityUnit NVARCHAR(2000),
ItemSize DECIMAL(18, 2),
PackageSize DECIMAL(18, 2),
FamilyCode NVARCHAR(20),
Family NVARCHAR(500),
CategoryCode NVARCHAR(20),
Category NVARCHAR(500),
SubCategoryCode NVARCHAR(20),
SubCategory NVARCHAR(500),
ItemGroupCode NVARCHAR(20),
ItemGroup NVARCHAR(500),
PurchaseValue DECIMAL(18, 2),
UnitPurchaseValue DECIMAL(18, 2),
PackagePurchaseValue DECIMAL(18, 2),
FacilityCode NVARCHAR(450),
CurrencyCode NVARCHAR(5)
我想 select 与 BatchRecords
ItemNames
不同 table 与具有相同 [=16] 的项目中的最大值 Id
配对=] 以及 Supplier
、Quantity
和项目的其他值,每个 ItemName
的最大值为 Id
。到目前为止,我想出了以下 SP,但肯定还行不通,因为 GROUP BY
会抛出错误。
我或许可以使用子查询,但是我如何满足每个唯一 ItemName
的最大 ID 条件?此外,对存储过程 quality/obvious 瓶颈的任何输入都非常感谢,因为它必须有点快。
CREATE PROCEDURE dbo.GetRecordsPageFlat
(@BatchIds dbo.GenericIntArray READONLY,
@FileRequestId INT,
@PageSize INT,
@PageCount INT,
@LastId BIGINT,
@NameMaskValue NVARCHAR(128) = NULL,
@NameMaskType INT = NULL,
@FamilyCodeMaskValue NVARCHAR(128),
@CategoryCodeMaskValue NVARCHAR(128),
@SubCategoryCodeMaskValue NVARCHAR(128)
)
AS
SET NOCOUNT ON;
DECLARE @Temp dbo.RecordImportStructure
DECLARE @ErrorCode INT
DECLARE @Step NVARCHAR(200)
DECLARE @Rows INT
--OUTPUT @@ROWCOUNT
--OUTPUT INSERTED.Id
INSERT INTO @Temp (
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
PurchaseValue,
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
)
SELECT
BR.Id,
BR.ItemName,
BR.Supplier,
BR.Quantity,
BR.ItemUnit,
BR.EntityUnit,
BR.ItemSize,
BR.PackageSize,
BR.ItemGroup,
BR.UnitPurchaseValue,
BR.PackagePurchaseValue,
C.IsoCode
FROM
dbo.BatchRecords BR
LEFT OUTER JOIN
dbo.FacilityInstances F ON F.Id = BR.FacilityInstanceId
LEFT OUTER JOIN
dbo.Currencies C ON C.Id = BR.CurrencyId
--OPTION(RECOMPILE)
WHERE
BR.DataBatchId IN (SELECT * FROM @BatchIds)
AND BR.Id > @LastId
AND (@FamilyCodeMaskValue IS NULL OR BR.FamilyCode = @FamilyCodeMaskValue)
AND (@CategoryCodeMaskValue IS NULL OR BR.CategoryCode = @CategoryCodeMaskValue)
AND (@SubCategoryCodeMaskValue IS NULL OR BR.SubCategoryCode = @SubCategoryCodeMaskValue)
AND (@NameMaskType IS NULL AND @NameMaskValue IS NULL
OR ((@NameMaskType = 1 AND BR.ItemName LIKE @NameMaskValue + '%')
OR (@NameMaskType = 2 AND BR.ItemName LIKE '%' + @NameMaskValue)
OR (@NameMaskType = 3 AND BR.ItemName LIKE '%' + @NameMaskValue + '%')
))
GROUP BY
BR.ItemName
ORDER BY
BR.Id
OFFSET @PageCount * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
UPDATE dbo.BatchActionRequests
SET PageNumber = @PageCount+1,
LatestItemId = (SELECT MAX(Id) FROM @Temp)
WHERE Id = @FileRequestId
;WITH CTC
AS
(
SELECT MAX(BR.ID) AS Id, BR.ItemName
FROM dbo.BatchRecords BR
LEFT OUTER JOIN dbo.FacilityInstances F ON F.Id = BR.FacilityInstanceId
WHERE BR.DataBatchId IN (SELECT * FROM @BatchIds)
AND BR.Id > @LastId
AND (@FamilyCodeMaskValue IS NULL OR BR.FamilyCode = @FamilyCodeMaskValue)
AND (@CategoryCodeMaskValue IS NULL OR BR.CategoryCode = @CategoryCodeMaskValue)
AND (@SubCategoryCodeMaskValue IS NULL OR BR.SubCategoryCode = @SubCategoryCodeMaskValue)
AND (@NameMaskType IS NULL AND @NameMaskValue IS NULL
OR ((@NameMaskType = 1 AND BR.ItemName LIKE @NameMaskValue + '%')
OR (@NameMaskType = 2 AND BR.ItemName LIKE '%' + @NameMaskValue)
OR (@NameMaskType = 3 AND BR.ItemName LIKE '%' + @NameMaskValue + '%')
))
GROUP BY
BR.ItemName
)
INSERT INTO @Temp (
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
PurchaseValue,
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
)
SELECT BR.Id,
BR.ItemName,
BR.Supplier,
BR.Quantity,
BR.ItemUnit,
BR.EntityUnit,
BR.ItemSize,
BR.PackageSize,
BR.ItemGroup,
BR.UnitPurchaseValue,
BR.PackagePurchaseValue,
C.IsoCode
FROM CTC t
JOIN dbo.BatchRecords BR ON t.Id = BR.Id
LEFT OUTER JOIN dbo.Currencies C ON C.Id = BR.CurrencyId
ORDER BY BR.Id
OFFSET @PageCount * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
看起来像 top-n-per-group
问题。
有两种常见的方法:使用 ROW_NUMBER
和 CROSS APPLY
。这是 ROW_NUMBER
变体。有关详细信息,请参阅 Get top 1 row of each group。
WITH
CTE
AS
(
SELECT
BR.Id,
BR.ItemName,
BR.Supplier,
BR.Quantity,
BR.ItemUnit,
BR.EntityUnit,
BR.ItemSize,
BR.PackageSize,
-- BR.ItemGroup,???
BR.UnitPurchaseValue,
BR.PackagePurchaseValue,
C.IsoCode AS CurrencyCode,
ROW_NUMBER() OVER (PARTITION BY BR.ItemName ORDER BY BR.Id DESC) AS rn
FROM
dbo.BatchRecords BR
LEFT OUTER JOIN dbo.FacilityInstances F ON F.Id = BR.FacilityInstanceId
LEFT OUTER JOIN dbo.Currencies C ON C.Id = BR.CurrencyId
WHERE
BR.DataBatchId IN (SELECT * FROM @BatchIds)
AND BR.Id > @LastId
AND (@FamilyCodeMaskValue IS NULL OR BR.FamilyCode = @FamilyCodeMaskValue)
AND (@CategoryCodeMaskValue IS NULL OR BR.CategoryCode = @CategoryCodeMaskValue)
AND (@SubCategoryCodeMaskValue IS NULL OR BR.SubCategoryCode = @SubCategoryCodeMaskValue)
AND (@NameMaskType IS NULL AND @NameMaskValue IS NULL
OR ((@NameMaskType = 1 AND BR.ItemName LIKE @NameMaskValue + '%')
OR (@NameMaskType = 2 AND BR.ItemName LIKE '%' + @NameMaskValue)
OR (@NameMaskType = 3 AND BR.ItemName LIKE '%' + @NameMaskValue + '%')
))
)
INSERT INTO @Temp (
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
-- PurchaseValue,???
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
)
SELECT
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
-- PurchaseValue,???
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
FROM CTE
WHERE rn = 1
ORDER BY
Id
OFFSET @PageCount * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY
OPTION(RECOMPILE);
对于每个 ItemName
,查询将选择具有最大 Id
的行。
我正在使用 SQL Server 2014。我的结构如下:
Id BIGINT,
ItemName NVARCHAR(4000),
RecordDate DATETIME2,
Supplier NVARCHAR(450),
Quantity DECIMAL(18, 2),
ItemUnit NVARCHAR(2000),
EntityUnit NVARCHAR(2000),
ItemSize DECIMAL(18, 2),
PackageSize DECIMAL(18, 2),
FamilyCode NVARCHAR(20),
Family NVARCHAR(500),
CategoryCode NVARCHAR(20),
Category NVARCHAR(500),
SubCategoryCode NVARCHAR(20),
SubCategory NVARCHAR(500),
ItemGroupCode NVARCHAR(20),
ItemGroup NVARCHAR(500),
PurchaseValue DECIMAL(18, 2),
UnitPurchaseValue DECIMAL(18, 2),
PackagePurchaseValue DECIMAL(18, 2),
FacilityCode NVARCHAR(450),
CurrencyCode NVARCHAR(5)
我想 select 与 BatchRecords
ItemNames
不同 table 与具有相同 [=16] 的项目中的最大值 Id
配对=] 以及 Supplier
、Quantity
和项目的其他值,每个 ItemName
的最大值为 Id
。到目前为止,我想出了以下 SP,但肯定还行不通,因为 GROUP BY
会抛出错误。
我或许可以使用子查询,但是我如何满足每个唯一 ItemName
的最大 ID 条件?此外,对存储过程 quality/obvious 瓶颈的任何输入都非常感谢,因为它必须有点快。
CREATE PROCEDURE dbo.GetRecordsPageFlat
(@BatchIds dbo.GenericIntArray READONLY,
@FileRequestId INT,
@PageSize INT,
@PageCount INT,
@LastId BIGINT,
@NameMaskValue NVARCHAR(128) = NULL,
@NameMaskType INT = NULL,
@FamilyCodeMaskValue NVARCHAR(128),
@CategoryCodeMaskValue NVARCHAR(128),
@SubCategoryCodeMaskValue NVARCHAR(128)
)
AS
SET NOCOUNT ON;
DECLARE @Temp dbo.RecordImportStructure
DECLARE @ErrorCode INT
DECLARE @Step NVARCHAR(200)
DECLARE @Rows INT
--OUTPUT @@ROWCOUNT
--OUTPUT INSERTED.Id
INSERT INTO @Temp (
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
PurchaseValue,
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
)
SELECT
BR.Id,
BR.ItemName,
BR.Supplier,
BR.Quantity,
BR.ItemUnit,
BR.EntityUnit,
BR.ItemSize,
BR.PackageSize,
BR.ItemGroup,
BR.UnitPurchaseValue,
BR.PackagePurchaseValue,
C.IsoCode
FROM
dbo.BatchRecords BR
LEFT OUTER JOIN
dbo.FacilityInstances F ON F.Id = BR.FacilityInstanceId
LEFT OUTER JOIN
dbo.Currencies C ON C.Id = BR.CurrencyId
--OPTION(RECOMPILE)
WHERE
BR.DataBatchId IN (SELECT * FROM @BatchIds)
AND BR.Id > @LastId
AND (@FamilyCodeMaskValue IS NULL OR BR.FamilyCode = @FamilyCodeMaskValue)
AND (@CategoryCodeMaskValue IS NULL OR BR.CategoryCode = @CategoryCodeMaskValue)
AND (@SubCategoryCodeMaskValue IS NULL OR BR.SubCategoryCode = @SubCategoryCodeMaskValue)
AND (@NameMaskType IS NULL AND @NameMaskValue IS NULL
OR ((@NameMaskType = 1 AND BR.ItemName LIKE @NameMaskValue + '%')
OR (@NameMaskType = 2 AND BR.ItemName LIKE '%' + @NameMaskValue)
OR (@NameMaskType = 3 AND BR.ItemName LIKE '%' + @NameMaskValue + '%')
))
GROUP BY
BR.ItemName
ORDER BY
BR.Id
OFFSET @PageCount * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
UPDATE dbo.BatchActionRequests
SET PageNumber = @PageCount+1,
LatestItemId = (SELECT MAX(Id) FROM @Temp)
WHERE Id = @FileRequestId
;WITH CTC
AS
(
SELECT MAX(BR.ID) AS Id, BR.ItemName
FROM dbo.BatchRecords BR
LEFT OUTER JOIN dbo.FacilityInstances F ON F.Id = BR.FacilityInstanceId
WHERE BR.DataBatchId IN (SELECT * FROM @BatchIds)
AND BR.Id > @LastId
AND (@FamilyCodeMaskValue IS NULL OR BR.FamilyCode = @FamilyCodeMaskValue)
AND (@CategoryCodeMaskValue IS NULL OR BR.CategoryCode = @CategoryCodeMaskValue)
AND (@SubCategoryCodeMaskValue IS NULL OR BR.SubCategoryCode = @SubCategoryCodeMaskValue)
AND (@NameMaskType IS NULL AND @NameMaskValue IS NULL
OR ((@NameMaskType = 1 AND BR.ItemName LIKE @NameMaskValue + '%')
OR (@NameMaskType = 2 AND BR.ItemName LIKE '%' + @NameMaskValue)
OR (@NameMaskType = 3 AND BR.ItemName LIKE '%' + @NameMaskValue + '%')
))
GROUP BY
BR.ItemName
)
INSERT INTO @Temp (
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
PurchaseValue,
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
)
SELECT BR.Id,
BR.ItemName,
BR.Supplier,
BR.Quantity,
BR.ItemUnit,
BR.EntityUnit,
BR.ItemSize,
BR.PackageSize,
BR.ItemGroup,
BR.UnitPurchaseValue,
BR.PackagePurchaseValue,
C.IsoCode
FROM CTC t
JOIN dbo.BatchRecords BR ON t.Id = BR.Id
LEFT OUTER JOIN dbo.Currencies C ON C.Id = BR.CurrencyId
ORDER BY BR.Id
OFFSET @PageCount * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY;
看起来像 top-n-per-group
问题。
有两种常见的方法:使用 ROW_NUMBER
和 CROSS APPLY
。这是 ROW_NUMBER
变体。有关详细信息,请参阅 Get top 1 row of each group。
WITH
CTE
AS
(
SELECT
BR.Id,
BR.ItemName,
BR.Supplier,
BR.Quantity,
BR.ItemUnit,
BR.EntityUnit,
BR.ItemSize,
BR.PackageSize,
-- BR.ItemGroup,???
BR.UnitPurchaseValue,
BR.PackagePurchaseValue,
C.IsoCode AS CurrencyCode,
ROW_NUMBER() OVER (PARTITION BY BR.ItemName ORDER BY BR.Id DESC) AS rn
FROM
dbo.BatchRecords BR
LEFT OUTER JOIN dbo.FacilityInstances F ON F.Id = BR.FacilityInstanceId
LEFT OUTER JOIN dbo.Currencies C ON C.Id = BR.CurrencyId
WHERE
BR.DataBatchId IN (SELECT * FROM @BatchIds)
AND BR.Id > @LastId
AND (@FamilyCodeMaskValue IS NULL OR BR.FamilyCode = @FamilyCodeMaskValue)
AND (@CategoryCodeMaskValue IS NULL OR BR.CategoryCode = @CategoryCodeMaskValue)
AND (@SubCategoryCodeMaskValue IS NULL OR BR.SubCategoryCode = @SubCategoryCodeMaskValue)
AND (@NameMaskType IS NULL AND @NameMaskValue IS NULL
OR ((@NameMaskType = 1 AND BR.ItemName LIKE @NameMaskValue + '%')
OR (@NameMaskType = 2 AND BR.ItemName LIKE '%' + @NameMaskValue)
OR (@NameMaskType = 3 AND BR.ItemName LIKE '%' + @NameMaskValue + '%')
))
)
INSERT INTO @Temp (
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
-- PurchaseValue,???
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
)
SELECT
Id,
ItemName,
Supplier,
Quantity,
ItemUnit,
EntityUnit,
ItemSize,
PackageSize,
-- PurchaseValue,???
UnitPurchaseValue,
PackagePurchaseValue,
CurrencyCode
FROM CTE
WHERE rn = 1
ORDER BY
Id
OFFSET @PageCount * @PageSize ROWS
FETCH NEXT @PageSize ROWS ONLY
OPTION(RECOMPILE);
对于每个 ItemName
,查询将选择具有最大 Id
的行。