SQL 跨行分配值
SQL distribute values across rows
SQL 不是我的强项,我需要帮助。我正在尝试将我从 table 中选择的最大值分散到多行中。假设我从最大值 5 (B.MaxVal = 5
) 开始,我有 3 行要拆分(有 3 个相同的实例 B.bId
)。
我想取 5 的值并推导出每个实例都得到一些东西的结果。如果我们将 5 的值除以 3,我将得到一个不好的浮点数。相反,我希望在 B.bId
的 3 个实例中将 5 分配为 2、2、1
select distinct
A.aId, B.bId, B.MaxVal,
B.MaxVal / Count(B.bId) OVER(PARTITION BY B.bId) AS 'AVG'
from
CPN
inner join
PN on CPN.aId = PN.id
inner join
A on A.aId = CPN.aId
left join
B on PN.bId = B.bId
where
(some search param)
group by
A.aId, B.bId, B.MaxVal
A 和 B 不同 table。
编辑:修改为使用 FLOOR()
函数并根据您的评论更改了不等式。
我会尝试这样的事情:
FLOOR(B.MaxVal / COUNT(B.bId) OVER (PARTITION BY B.bId))
+ CASE
WHEN ROW_NUMBER() OVER (PARTITION BY b.bId ORDER BY b.bId) <= (B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId)) THEN 1
ELSE 0
END as "DISTRIBUTED_AVG"
第一位是您已经在做的除法。 ROUND()
在 SQL 服务器 also serves as the truncate function 中。 ROUND(<expression>,0,1)
将截断小数点处的值。 使用 FLOOR()
函数。
接下来就复杂了。您的描述基本上是我们需要将最大值除以计数的剩余部分展开。好吧,除法的其余部分是模函数。所以,我们知道我们可能需要使用它。 (B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId))
就是这样。
接下来,我们需要以某种方式知道我们用完了多少余数。因为我们只处理余数,所以我们知道我们永远不需要为任何值提供超过一项的额外项目。这也意味着我们将 "consume" 余数以每行 1 的速率计算。所以,我们需要知道我们在组中的哪一行。为此,我使用了 ROW_NUMBER()
函数。它的分区与 COUNT()
相同,因此它将具有相同的分组。您唯一可能想要更改的是 ORDER BY;我刚刚选了一些东西。基本上,我们知道当余数等于或小于我们经过的行数时,我们就有了余数,嗯,剩余。
我觉得我的数学有点不对劲或者我漏掉了什么,但是,因为我现在有点累了。我鼓励您分别查看其中的每一个以了解其作用:
SELECT DISTINCT A.aId,
B.bId,
B.MaxVal,
B.MaxVal / Count(B.bId) OVER (PARTITION BY B.bId) AS 'AVG'
FLOOR(B.MaxVal / COUNT(B.bId) OVER (PARTITION BY B.bId)),
ROW_NUMBER() OVER (PARTITION BY b.bId ORDER BY b.bId),
B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId),
ROUND(B.MaxVal / COUNT(B.bId) OVER (PARTITION BY B.bId),0,1)
+ CASE
WHEN ROW_NUMBER() OVER (PARTITION BY b.bId ORDER BY b.bId) <= (B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId)) THEN 1
ELSE 0
END as "DISTRIBUTED_AVG"
FROM [...]
SQL 不是我的强项,我需要帮助。我正在尝试将我从 table 中选择的最大值分散到多行中。假设我从最大值 5 (B.MaxVal = 5
) 开始,我有 3 行要拆分(有 3 个相同的实例 B.bId
)。
我想取 5 的值并推导出每个实例都得到一些东西的结果。如果我们将 5 的值除以 3,我将得到一个不好的浮点数。相反,我希望在 B.bId
的 3 个实例中将 5 分配为 2、2、1select distinct
A.aId, B.bId, B.MaxVal,
B.MaxVal / Count(B.bId) OVER(PARTITION BY B.bId) AS 'AVG'
from
CPN
inner join
PN on CPN.aId = PN.id
inner join
A on A.aId = CPN.aId
left join
B on PN.bId = B.bId
where
(some search param)
group by
A.aId, B.bId, B.MaxVal
A 和 B 不同 table。
编辑:修改为使用 FLOOR()
函数并根据您的评论更改了不等式。
我会尝试这样的事情:
FLOOR(B.MaxVal / COUNT(B.bId) OVER (PARTITION BY B.bId))
+ CASE
WHEN ROW_NUMBER() OVER (PARTITION BY b.bId ORDER BY b.bId) <= (B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId)) THEN 1
ELSE 0
END as "DISTRIBUTED_AVG"
第一位是您已经在做的除法。 使用 ROUND()
在 SQL 服务器 also serves as the truncate function 中。 ROUND(<expression>,0,1)
将截断小数点处的值。FLOOR()
函数。
接下来就复杂了。您的描述基本上是我们需要将最大值除以计数的剩余部分展开。好吧,除法的其余部分是模函数。所以,我们知道我们可能需要使用它。 (B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId))
就是这样。
接下来,我们需要以某种方式知道我们用完了多少余数。因为我们只处理余数,所以我们知道我们永远不需要为任何值提供超过一项的额外项目。这也意味着我们将 "consume" 余数以每行 1 的速率计算。所以,我们需要知道我们在组中的哪一行。为此,我使用了 ROW_NUMBER()
函数。它的分区与 COUNT()
相同,因此它将具有相同的分组。您唯一可能想要更改的是 ORDER BY;我刚刚选了一些东西。基本上,我们知道当余数等于或小于我们经过的行数时,我们就有了余数,嗯,剩余。
我觉得我的数学有点不对劲或者我漏掉了什么,但是,因为我现在有点累了。我鼓励您分别查看其中的每一个以了解其作用:
SELECT DISTINCT A.aId,
B.bId,
B.MaxVal,
B.MaxVal / Count(B.bId) OVER (PARTITION BY B.bId) AS 'AVG'
FLOOR(B.MaxVal / COUNT(B.bId) OVER (PARTITION BY B.bId)),
ROW_NUMBER() OVER (PARTITION BY b.bId ORDER BY b.bId),
B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId),
ROUND(B.MaxVal / COUNT(B.bId) OVER (PARTITION BY B.bId),0,1)
+ CASE
WHEN ROW_NUMBER() OVER (PARTITION BY b.bId ORDER BY b.bId) <= (B.MaxVal % COUNT(B.bId) OVER (PARTITION BY B.bId)) THEN 1
ELSE 0
END as "DISTRIBUTED_AVG"
FROM [...]