Ker*_*mit 1 sql sql-server sql-server-2008-r2
使用以下结果集:
| DATE | BUSINESS | COLLEAGUE | POSITION | HOURS | STANDARDHOURS | COUNTER | OVER16 | OVER32 | OVER48 | ----------------------------------------------------------------------------------------------------------------- | 2013-01-01 | a | bob jones | analyst | 168 | 168 | 1 | 0 | 0 | 0 | | 2013-01-01 | a | cindy jones | assistant | 184 | 168 | 1 | 1 | 0 | 0 | | 2013-01-01 | b | tim harris | programmer | 200 | 168 | 1 | 1 | 1 | 0 | | 2013-01-01 | b | tom white | manager | 216 | 168 | 1 | 1 | 1 | 1 | | 2013-02-01 | a | bob jones | analyst | 176 | 176 | 1 | 0 | 0 | 0 | | 2013-02-01 | a | cindy jones | assistant | 176 | 176 | 1 | 0 | 0 | 0 | | 2013-02-01 | b | tim harris | programmer | 200 | 176 | 1 | 1 | 0 | 0 | | 2013-02-01 | b | tom white | manager | 216 | 176 | 1 | 1 | 1 | 0 |
使用此查询:
SELECT c.date,
c.business,
CASE
WHEN Sum(c.over16) > 0 THEN ( Sum(c.over16) / Sum(c.counter) ) * 100
ELSE 0
END AS percOver16,
CASE
WHEN Sum(c.over32) > 0 THEN ( Sum(c.over32) / Sum(c.counter) ) * 100
ELSE 0
END AS percOver32,
CASE
WHEN Sum(c.over48) > 0 THEN ( Sum(c.over48) / Sum(c.counter) ) * 100
ELSE 0
END AS percOver48
FROM (SELECT a.date,
a.business,
a.colleague,
a.position,
a.hours,
b.standardhours,
1 AS counter,
CASE
WHEN a.hours >= b.standardhours + 16 THEN 1
ELSE 0
END AS over16,
CASE
WHEN a.hours >= b.standardhours + 32 THEN 1
ELSE 0
END AS over32,
CASE
WHEN a.hours >= b.standardhours + 48 THEN 1
ELSE 0
END AS over48
FROM colleaguetime a
JOIN businesshours b
ON b.date = a.date) c
GROUP BY c.date,
c.business
Run Code Online (Sandbox Code Playgroud)
我明白了:
| DATE | BUSINESS | PERCOVER16 | PERCOVER32 | PERCOVER48 | ---------------------------------------------------------------- | 2013-01-01 | a | 0 | 0 | 0 | | 2013-01-01 | b | 100 | 100 | 0 | | 2013-02-01 | a | 0 | 0 | 0 | | 2013-02-01 | b | 100 | 0 | 0 |
期望的结果是:
| DATE | BUSINESS | PERCOVER16 | PERCOVER32 | PERCOVER48 | ---------------------------------------------------------------- | 2013-01-01 | a | 50 | 0 | 0 | | 2013-01-01 | b | 100 | 100 | 50 | | 2013-02-01 | a | 0 | 0 | 0 | | 2013-02-01 | b | 100 | 50 | 0 |
使用CTE有更简单的方法吗?
我相信你遇到的问题是整数除法问题.您希望在进行除法之前将值转换为十进制或浮点格式.这是一种方法:
SELECT c.date,
c.business,
CASE
WHEN Sum(c.over16) > 0 THEN ( Sum(c.over16*1.0) / Sum(c.counter) ) * 100
ELSE 0
END AS percOver16,
CASE
WHEN Sum(c.over32) > 0 THEN ( Sum(c.over32*1.0) / Sum(c.counter) ) * 100
ELSE 0
END AS percOver32,
CASE
WHEN Sum(c.over48) > 0 THEN ( Sum(c.over48*1.0) / Sum(c.counter) ) * 100
ELSE 0
END AS percOver48
Run Code Online (Sandbox Code Playgroud)
编辑:
最简单的替代方法是在子查询中更改计数器的定义:
1.0 as counter, -- This has a decimal point so it can be used for division
Run Code Online (Sandbox Code Playgroud)
这会将其定义为非整数数字数据类型.
作为生产代码的一般规则,我喜欢在分区发生时进行这些转换,以防止意外错误.在某个地方,你或其他人可以看到一条线,1.0 as counter并认为"那是愚蠢的. Counter应该是一个整数." 然后你或他或她改变它,然后东西就会破裂.或者有人看到sum(c.counter)并且认为"这是愚蠢的.它可以做count(*)或者count(c.counter).
另一方面,对于ad-hoc代码,我可能只是制作计数器1.0.
您可以通过在子查询中使用以下内容来解决此问题:
SELECT a.date, a.business, a.colleague, a.position, a.hours, b.standardHours,
1 AS counter,
CASE WHEN a.hours >= b.standardHours + 16
THEN 1.0 ELSE 0.0 END AS over16,
CASE WHEN a.hours >= b.standardHours + 32
THEN 1.0 ELSE 0.0 END AS over32,
CASE WHEN a.hours >= b.standardHours + 48
THEN 1.0 ELSE 0.0 END AS over48
FROM colleagueTime a
JOIN businessHours b ON b.date = a.date;
Run Code Online (Sandbox Code Playgroud)
见演示
而不是使用1和0,更改值,1.0因此它们是小数而不是整数.
或者正如戈登指出的那样,你可以使用1.0作为计数器值:
SELECT a.date, a.business, a.colleague, a.position, a.hours, b.standardHours,
1.0 AS counter,
CASE WHEN a.hours >= b.standardHours + 16
THEN 1 ELSE 0 END AS over16,
CASE WHEN a.hours >= b.standardHours + 32
THEN 1 ELSE 0 END AS over32,
CASE WHEN a.hours >= b.standardHours + 48
THEN 1 ELSE 0 END AS over48
FROM colleagueTime a
JOIN businessHours b ON b.date = a.date;
Run Code Online (Sandbox Code Playgroud)
更改
Sum(c.over16) / Sum(c.counter)
Run Code Online (Sandbox Code Playgroud)
至:
cast(SUM(c.over16) as float) / cast(SUM(c.counter) as float)
Run Code Online (Sandbox Code Playgroud)
(以及所有其他的.)
划分整数会产生整数.你需要先施放浮动.