我有一张包含姓名,类型和价值的表格。
DECLARE @t_Table TABLE
(
Name VARCHAR(10),
[Type] VARCHAR(10),
Value INT
)
INSERT INTO @t_Table
VALUES('Jill', 'Yellow', 100)
INSERT INTO @t_Table
VALUES('Jill', 'Blue', 200)
INSERT INTO @t_Table
VALUES('Jill', 'Green', 300)
INSERT INTO @t_Table
VALUES('Jill', 'Green', 400)
INSERT INTO @t_Table
VALUES('Jill', 'Green', 500)
INSERT INTO @t_Table
VALUES('Bob', 'Yellow', 100)
INSERT INTO @t_Table
VALUES('Bob', 'Blue', 200)
INSERT INTO @t_Table
VALUES('Bob', 'Green', 300)
INSERT INTO @t_Table
VALUES('Bob', 'Orange', 400)
INSERT INTO @t_Table
VALUES('Bob', 'Orange', 400)
INSERT INTO @t_Table
VALUES('Bob', 'Purple', 500)
INSERT INTO @t_Table
VALUES('Steve', 'Yellow', 100)
INSERT INTO @t_Table
VALUES('Steve', 'Blue', 200)
INSERT INTO @t_Table
VALUES('Steve', 'Green', 300)
INSERT INTO @t_Table
VALUES('Steve', 'Orange', 400)
INSERT INTO @t_Table
VALUES('Steve', 'Orange', 400)
我想获取名称组的总值,其中组中的基础记录满足特定类型出现的约束。 我想在HAVING子句中使用单个聚合来完成此任务。
如果我想要一个只有一个 x 类型记录的组,只需要一个 y 类型的记录,零个或多个 z类型的记录并没有其他记录,我已经达到了以下解决方案,例如,当我想要一个黄色,一个蓝色和零个或更多绿色时:
SELECT Name,
TotalValue = SUM(Value)
FROM @t_Table
GROUP BY Name
HAVING SUM(CASE WHEN [Type] = 'Yellow' THEN 1
WHEN [Type] = 'Blue' THEN 2
WHEN [Type] = 'Green' THEN 0
ELSE 4 END) = 3
正确返回此结果:
Name TotalValue
---------- -----------
Jill 1500
我将如何构建以下内容?
SELECT Name,
TotalValue = SUM(Value)
FROM @t_Table
GROUP BY Name
/*HAVING exactly one record with [Type] = 'Yellow'
and exactly one record with [Type] = 'Blue'
and exactly one record with [Type] = 'Green'
and zero or more records with [Type] = 'Orange'
and no records of any other type
*/
如果给出上述数据的预期结果将是
Name TotalValue
---------- -----------
Steve 1400
我知道以下解决方案(下面),但我需要一个在HAVING
子句中有一个聚合的解决方案。我也对另一个解决我的问题的查询结构持开放态度,只要它与我提出的结构一样简单或简单,并且表现相似或更好。
SELECT
Name,
TotalValue = SUM(Value)
FROM
@t_Table
GROUP BY
Name
HAVING
SUM(CASE WHEN [Type] = 'Yellow' THEN 1 ELSE NULL END) = 1
AND SUM(CASE WHEN [Type] = 'Blue' THEN 1 ELSE NULL END) = 1
AND SUM(CASE WHEN [Type] = 'Green' THEN 1 ELSE NULL END) = 1
AND SUM(CASE WHEN [Type] IN ('Yellow','Blue','Green','Orange') THEN 0 ELSE 1 END) = 0
答案 0 :(得分:1)
如何使用您的概念,但每种类型都有小数:
<强> SqlFiddleDemo 强>
data.table
这意味着正好是1黄色,1蓝色,1绿色。
使用SELECT Name,
TotalValue = SUM(Value)
FROM @t_Table
GROUP BY Name
HAVING SUM(
CASE [Type]
WHEN 'Yellow' THEN 1
WHEN 'Blue' THEN 10
WHEN 'Green' THEN 100
WHEN 'Orange' THEN 0
ELSE 0
END) = 111
或BETWEEN
可以实现更复杂的条件。一个注意事项只要你在一个组中搜索最多9个就行了。
如果您害怕因基于10的系统而导致溢出,请考虑使用基于1000的系统,例如:
< <= > =
答案 1 :(得分:1)
想象一下,在HAVING子句中,您可以比较两个多项式 然后想象你定义(从你拥有的数据)这个多项式:
count_YELLOW * x ^ 3 + count_BLUE * x ^ 2 + count_GREEN * x ^ 1 + count_ORANGE
/ * 用[Type] ='Yellow'记录一条记录 和[Type] ='Blue'的确切记录 和[Type] ='Green'的确切记录 和[Type] ='Orange'的零个或多个记录 并且没有任何其他类型的记录 * /
现在......在HAVING子句中表达你想要的东西,你会说:
HAVING
count_YELLOW * x^3 +
count_BLUE * x^2 +
count_GREEN * x^1 +
count_ORANGE >=
1 * x^3 +
1 * x^2 +
1 * x^1 +
0
AND
count_YELLOW * x^3 +
count_BLUE * x^2 +
count_GREEN * x^1 +
count_ORANGE <
1 * x^4
现在......
只需选择x = sum (all counts) + 1
,
或x = max (all counts) + 1
,
你可以把它变成数字。
我认为这会奏效。我明天可以在T-SQL中试一试
你会遇到一些大数字。这是不可避免的,
因为你想要将4个数字的矢量无差别地编码成一个数字。
答案 2 :(得分:0)
我认为这个查询效率更高
with cte as
(
select name, [type] tp, nb = count(*)
from @t_table
group by name, [type]
)
Select t1.name, sum(t1.Value)
from @ t_table t1 inner join cte t2 on t1.name = t2.name
where nb = (case t2.tp when 'Yellow' then 1
when 'Blue' then 1
...
end)
AND Exist (select * from cte where name = t2.name and t2.tp = 'Yellow')
AND Exist (select * from cte where name = t2.name and t2.tp = 'Blue')
...
group by t1.name