3

我有一个奇怪的要求,我需要在 SQL Server 2008 R2 的存储过程中使用它。

我需要一个返回序列的第一个元素的 FIRST 聚合函数,我将使用它的 withHAVING子句。

让我给你举个例子:

DECLARE @fooTable AS TABLE(
    ID INT,
    CategoryName NVARCHAR(100),
    Name NVARCHAR(100),
    MinAllow INT,
    Price DECIMAL(18,2)
);

INSERT INTO @fooTable  VALUES(1, 'Cat1', 'Product1', 2, 112.2);
INSERT INTO @fooTable  VALUES(2, 'Cat2', 'Product2', 4, 12.34);
INSERT INTO @fooTable  VALUES(3, 'Cat1', 'Product3', 5, 233.32);
INSERT INTO @fooTable  VALUES(4, 'Cat3', 'Product4', 4, 12.43);
INSERT INTO @fooTable  VALUES(5, 'Cat3', 'Product5', 1, 13.00);

DECLARE @minAllowParam AS INT = 3;

SELECT ft.CategoryName, SUM(ft.Price) FROM @fooTable ft
GROUP BY ft.CategoryName;

如您所见,我们有一个表格和一些虚拟值。在SELECT查询中,我们将类别组合在一起并将产品的价格相加。

此查询返回以下结果:

CategoryName     TotalPrice
---------------- ----------------
Cat1              345.52
Cat2              12.34
Cat3              25.43

我在这里需要的是这样的:

SELECT ft.CategoryName, SUM(ft.Price) FROM @fooTable ft
GROUP BY ft.CategoryName
HAVING GetFIRST(MinAllow) >= @minAllowParam;

在我们使用类似这样的查询的情况下,我们应该能够选择以下结果:

INSERT INTO @fooTable  VALUES(2, 'Cat2', 'Product2', 4, 12.34);
INSERT INTO @fooTable  VALUES(4, 'Cat3', 'Product4', 4, 12.43);
INSERT INTO @fooTable  VALUES(5, 'Cat3', 'Product5', 1, 13.00);

由于INSERT INTO @fooTable VALUES(1, 'Cat1', 'Product1', 2, 112.2);记录是序列的第一个元素并且MinAllow列的值为 2,因此Cat1应该超出范围。另一方面,INSERT INTO @fooTable VALUES(5, 'Cat3', 'Product5', 1, 13.00);记录的列值为 1,MinAllow但它是序列的第二个元素。因此,Cat3是安全的,可以选择。

注意:MIN或者MAX不是我要找的!

我知道这个例子在逻辑上没有意义,但另一方面,我有一种情况,它完全可以,而且很难在这里解释。

有什么想法吗?

编辑:

我假设我可以通过创建 CLR 用户定义的聚合函数来实现我想要的,但如果有任何其他选择,我不想这样做

4

4 回答 4

3

怎么样

SELECT f1.CategoryName, SUM(f1.Price) 
FROM @fooTable AS f1
INNER JOIN (
    SELECT MinAllow, CategoryName
    FROM (
         SELECT MinAllow, CategoryName, ROW_NUMBER() OVER (PARTITION BY CategoryName ORDER BY ID) AS m
         FROM @fooTable
    ) AS f
    WHERE m = 1
) AS f2 ON f1.CategoryName = f2.CategoryName
WHERE f2.MinAllow >= @minAllowParam
GROUP BY f1.CategoryName

我知道不是一个非常优雅的查询。如果我再努力一点,也许我可以稍微调整一下!

编辑:好的,最里面的子查询应该是不必要的。这也应该有效:

SELECT f1.CategoryName, SUM(f1.Price) 
FROM @fooTable AS f1
INNER JOIN (
    SELECT MinAllow, CategoryName, ROW_NUMBER() OVER (PARTITION BY CategoryName ORDER BY ID) AS m
    FROM @fooTable
) AS f2 ON f1.CategoryName = f2.CategoryName
WHERE f2.m = 1 AND f2.MinAllow >= @minAllowParam
GROUP BY f1.CategoryName
于 2012-04-12T08:58:02.597 回答
2

更新:一个可读的查询:

SELECT ft.CategoryName, SUM(ft.Price) 
FROM fooTable ft
    cross apply
    (
       select top 1 MinAllow
         from fooTable a
        where a.CategoryName = ft.CategoryName
        order by ID
    ) a
where a.MinAllow >= @minAllowParam
GROUP BY ft.CategoryName;

您可以过滤具有第一个(按 id?)MinAllow >= @minAllowParam 的类别:

...
inner join 
(
   select 
   -- Add columns you might need
     CategoryName,
     Price
   from
     fooTable
   inner join
   (
     -- First ID in category
     select
       min(id) id
     from
       fooTable
     group by
       CategoryName
   ) firstID
   -- Back to all columns
     ON fooTable.ID = firstID.ID
   -- but only if category sequence starts properly
    AND fooTable.MinAllow >= @minAllowParam
) a
-- Allow MinAllow categories only
  ON fooTable.CategoryName = a.CategoryName
于 2012-04-12T08:51:48.930 回答
1

查看带有分区的 ROW_NUMBER() :

http://msdn.microsoft.com/en-us/library/ms186734.aspx

于 2012-04-12T08:50:46.233 回答
0

我知道有两种方法可以实现 FIRST 聚合函数:

ROW_NUMBER()

(WHERE ROW_NUMBER_COLUMN = 1)

http://msdn.microsoft.com/en-us/library/ms186734.aspx

SELECT ...., (SELECT TOP 1 FROM ... WHERE (outer table join) ORDER BY SOMETHING) AS [FIRST]
FROM ...
于 2012-04-12T08:56:20.647 回答