使用 Count 计算 SQL 中的百分比时未获得预期输出
Not getting expected output when calculating percentage in SQL using Count
我是 运行 一个查询,但它没有输出我期望的结果。我有下面的 table:
------------------------
security_ID | Date | Rep
------------------------
2256 |202001| 0
2257 |202002| 0
2257 |202003| 0
2256 |202002| 1
2256 |202003| 2
2257 |202003| 1
我基本上是在尝试找出列 Rep
从一个日期到下一个日期从 0 变为 1 的情况百分比,而前一个日期的 Rep
为 0,对于给定的 security_ID
。 Date
s 的差异应为 1(例如,202002-202001 = 1。此处日期为整数)用于计算。
这里,对于security_ID = 2256
,Percent = 100
从202001
到202002
,Rep
从0变为1,而在table 2256
为 0
的行数为 1。百分比的公式为:
百分比 =(Rep_current = 1 且 Rep_prev = 0 的案例数)/(Rep_prev = 0 的案例数)* 100
对于 security_ID = 2257,百分比 = 1/2 * 100 = 50
例如,我希望输出为:
----------------------------------
security_ID | Date | Rep | Percent
----------------------------------
2256 |202001| 0 | 100
2257 |202002| 0 | 50
2257 |202003| 0 | 50
2256 |202002| 1 | 100
2256 |202003| 2 | 100
2257 |202003| 1 | 50
我尝试按如下方式执行此操作:
SELECT security_ID, Date, Rep,
(COUNT(CASE WHEN Rep_prev = 0 and Rep = 1 then 1 else 0 end)/count(CASE WHEN Rep_prev = 0 then 1 else 0 end) * 100) as "Percent"
from
(
select t1.security_id,t1.date,t1.rep,
coalesce(t2.rep,0) as Rep_prev
from mytable t1
left join mytable t2
on t1.security_id = t2.security_id
and t2.date = t1.date - 1
)
GROUP BY SECURITY_ID, Date, Rep
但我得到的输出是:
----------------------------------
security_ID | Date | Rep | Percent
----------------------------------
2256 |202001| 0 | 100
2257 |202002| 0 | 100
2257 |202003| 0 | 100
2256 |202002| 1 | 100
2256 |202003| 2 | 100
2257 |202003| 1 | 100
不太确定我的逻辑哪里错了。
如果您想了解更多信息,请告诉我,因为很难表达这个想法。
你可以使用下面的逻辑(使用Windows函数)-
Select mt.security_id, mt.Date, mt.Rep, (numerator*100)/denominator As "Percent"
from
(Select security_id,
SUM(case when Rep_curr = 1 and coalesce(Rep_prev,-99) = 0 then 1 else 0 end) As numerator,
SUM(case when coalesce(Rep_prev,-99) = 0 then 1 else 0 end) As denominator
from
(Select security_id,
Rep As Rep_curr,
lag(Rep,1) over(partition by security_id order by Date) As Rep_prev
from my_table) t
where t.Rep_prev is not NULL
group by security_id) tab
join my_table mt
on tab.security_id = mt.security_id;
这是一个数据库 fiddle link,演示了它在 SQL 服务器 - https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=8654f0242bbed911f1ed63b795281bac 中的工作原理。上述语法也适用于 Sybase。
编辑:
如果我要使用你的方法,我会这样做 -
SELECT mt.*, Tab1.Perct As "Percent"
FROM
(SELECT security_ID,
(SUM(CASE WHEN Rep_prev = 0 and Rep = 1 then 1 else 0 end) * 100/SUM(CASE WHEN Rep_prev = 0 then 1 else 0 end)) as Perct
from
(
select t1.security_id,t1.date,t1.rep,
coalesce(t2.rep,0) as Rep_prev
from mytable t1
left join mytable t2
on t1.security_id = t2.security_id
and t2.date = t1.date - 1
where t2.rep IS NOT NULL
) t
GROUP BY SECURITY_ID ) Tab1
JOIN mytable mt
ON TAB1.security_ID = mt.security_ID;
使用 window 函数,如下所示:
select t.*,
(sum(case when prev_rep = 0 and rep = 1 then 100.0 else 0 end) over (partition by security_id) /
sum(case when rep = 0 then 1 else 0 end) over (partition by security_id)
) as precent
from (select t.*,
lag(rep) over (partition by security_id order by date) as prev_rep
from mytable t
) t;
如果您使用的 Sybase 版本不支持 window 函数,那么您可以使用 security_id 计算此 :
select security_id,
(sum(case when prev_rep = 0 and rep = 1 then 100.0 else 0 end) /
sum(case when rep = 0 then 1 else 0 end)
) as precent
from (select t.*,
(select top (1) t2.rep
from mytable t2
where t2.security_id = t.security_id and
t2.date < t.date
order by t2.date desc
) as prev_rep
from mytable t
) t
group by security_id;
然后您可以 join
将其返回给您的 table 如果您每行都需要它。
编辑:
如果您每个月都有行,那么也许这行得通:
select security_id,
(sum(case when prev_rep = 0 and rep = 1 then 100.0 else 0 end) /
sum(case when rep = 0 then 1 else 0 end)
) as precent
from (select t.*, tprev.rep as prev_rep
from mytable t left join
mytable tprev
on t.security_id = tprev.security_id and
convert(date, tprev.date + '01') = dateadd(month, -1, convert(date, t.date + '01'))
) t
group by security_id;
注意:这假定 date
是一个字符串。将其存储为适当的 date
会简化逻辑。
我是 运行 一个查询,但它没有输出我期望的结果。我有下面的 table:
------------------------
security_ID | Date | Rep
------------------------
2256 |202001| 0
2257 |202002| 0
2257 |202003| 0
2256 |202002| 1
2256 |202003| 2
2257 |202003| 1
我基本上是在尝试找出列 Rep
从一个日期到下一个日期从 0 变为 1 的情况百分比,而前一个日期的 Rep
为 0,对于给定的 security_ID
。 Date
s 的差异应为 1(例如,202002-202001 = 1。此处日期为整数)用于计算。
这里,对于security_ID = 2256
,Percent = 100
从202001
到202002
,Rep
从0变为1,而在table 2256
为 0
的行数为 1。百分比的公式为:
百分比 =(Rep_current = 1 且 Rep_prev = 0 的案例数)/(Rep_prev = 0 的案例数)* 100
对于 security_ID = 2257,百分比 = 1/2 * 100 = 50
例如,我希望输出为:
----------------------------------
security_ID | Date | Rep | Percent
----------------------------------
2256 |202001| 0 | 100
2257 |202002| 0 | 50
2257 |202003| 0 | 50
2256 |202002| 1 | 100
2256 |202003| 2 | 100
2257 |202003| 1 | 50
我尝试按如下方式执行此操作:
SELECT security_ID, Date, Rep,
(COUNT(CASE WHEN Rep_prev = 0 and Rep = 1 then 1 else 0 end)/count(CASE WHEN Rep_prev = 0 then 1 else 0 end) * 100) as "Percent"
from
(
select t1.security_id,t1.date,t1.rep,
coalesce(t2.rep,0) as Rep_prev
from mytable t1
left join mytable t2
on t1.security_id = t2.security_id
and t2.date = t1.date - 1
)
GROUP BY SECURITY_ID, Date, Rep
但我得到的输出是:
----------------------------------
security_ID | Date | Rep | Percent
----------------------------------
2256 |202001| 0 | 100
2257 |202002| 0 | 100
2257 |202003| 0 | 100
2256 |202002| 1 | 100
2256 |202003| 2 | 100
2257 |202003| 1 | 100
不太确定我的逻辑哪里错了。
如果您想了解更多信息,请告诉我,因为很难表达这个想法。
你可以使用下面的逻辑(使用Windows函数)-
Select mt.security_id, mt.Date, mt.Rep, (numerator*100)/denominator As "Percent"
from
(Select security_id,
SUM(case when Rep_curr = 1 and coalesce(Rep_prev,-99) = 0 then 1 else 0 end) As numerator,
SUM(case when coalesce(Rep_prev,-99) = 0 then 1 else 0 end) As denominator
from
(Select security_id,
Rep As Rep_curr,
lag(Rep,1) over(partition by security_id order by Date) As Rep_prev
from my_table) t
where t.Rep_prev is not NULL
group by security_id) tab
join my_table mt
on tab.security_id = mt.security_id;
这是一个数据库 fiddle link,演示了它在 SQL 服务器 - https://dbfiddle.uk/?rdbms=sqlserver_2014&fiddle=8654f0242bbed911f1ed63b795281bac 中的工作原理。上述语法也适用于 Sybase。
编辑: 如果我要使用你的方法,我会这样做 -
SELECT mt.*, Tab1.Perct As "Percent"
FROM
(SELECT security_ID,
(SUM(CASE WHEN Rep_prev = 0 and Rep = 1 then 1 else 0 end) * 100/SUM(CASE WHEN Rep_prev = 0 then 1 else 0 end)) as Perct
from
(
select t1.security_id,t1.date,t1.rep,
coalesce(t2.rep,0) as Rep_prev
from mytable t1
left join mytable t2
on t1.security_id = t2.security_id
and t2.date = t1.date - 1
where t2.rep IS NOT NULL
) t
GROUP BY SECURITY_ID ) Tab1
JOIN mytable mt
ON TAB1.security_ID = mt.security_ID;
使用 window 函数,如下所示:
select t.*,
(sum(case when prev_rep = 0 and rep = 1 then 100.0 else 0 end) over (partition by security_id) /
sum(case when rep = 0 then 1 else 0 end) over (partition by security_id)
) as precent
from (select t.*,
lag(rep) over (partition by security_id order by date) as prev_rep
from mytable t
) t;
如果您使用的 Sybase 版本不支持 window 函数,那么您可以使用 security_id 计算此 :
select security_id,
(sum(case when prev_rep = 0 and rep = 1 then 100.0 else 0 end) /
sum(case when rep = 0 then 1 else 0 end)
) as precent
from (select t.*,
(select top (1) t2.rep
from mytable t2
where t2.security_id = t.security_id and
t2.date < t.date
order by t2.date desc
) as prev_rep
from mytable t
) t
group by security_id;
然后您可以 join
将其返回给您的 table 如果您每行都需要它。
编辑:
如果您每个月都有行,那么也许这行得通:
select security_id,
(sum(case when prev_rep = 0 and rep = 1 then 100.0 else 0 end) /
sum(case when rep = 0 then 1 else 0 end)
) as precent
from (select t.*, tprev.rep as prev_rep
from mytable t left join
mytable tprev
on t.security_id = tprev.security_id and
convert(date, tprev.date + '01') = dateadd(month, -1, convert(date, t.date + '01'))
) t
group by security_id;
注意:这假定 date
是一个字符串。将其存储为适当的 date
会简化逻辑。