我使用的是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)
我希望从ItemNames
表格中选择与BatchRecords
表中的Id
不同的ItemName
与Supplier
以及{{1} {}},Quantity
以及每个Id
的最大ItemName
项的其他值。到目前为止,我想出了以下SP,当它GROUP BY
抛出错误时它肯定还没有工作。
我可以使用子查询,但是如何满足每个唯一ItemName
的最大ID的条件?此外,对存储过程质量/明显瓶颈的任何输入都是高度赞赏的,因为它必须有点快。
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
答案 0 :(得分:1)
;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;
答案 1 :(得分:1)
看起来像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
的行。