count boolean column,并根据boolean列平均另一列

时间:2018-03-12 05:56:41

标签: sql postgresql select average

CREATE TABLE test (
    calculate_time int4 NULL,
    status bool NULL
);

INSERT INTO test (calculate_time,status) VALUES 
(10,true)
,(15,true)
,(20,true)
,(20,true)
,(5,false)
,(10,false)
,(15,false)
,(100,NULL)
,(200,NULL)
,(300,NULL)
;

使用此查询,它会平均所有calculated_time值。有没有办法可以告诉它只有status = true的平均值?我尝试添加一个where子句但会使失败和暂停的结果为0。

select 
    avg(calculate_time) as cal_time,
    count(case when status = true then 1 end) as completed,
    count(case when status = false then 1 end) as failed,
    count(case when status is null then 1 end) as suspended
from test;

2 个答案:

答案 0 :(得分:3)

您似乎理解条件聚合的概念。你也可以使用public abstract class CalendarPagerAdapter extends FragmentStatePagerAdapter { private static final String TAG = LogUtils.makeLogTag(CalendarPagerAdapter.class); protected DateTime mDateTime; private final int mCount; protected int mTodayPosition; public static class CalendarContext { public int mRange; // range = nb of days supported public int mTodayPosition; // Today index in this area public int mCurrentWeek; // Week number of today public DateTime mFrom, mTo; // Compute from and to datetimes public boolean mIsSundayFirstDay; public CalendarContext(int area, int todayPosition, DateTime from, DateTime to, int currentWeek, boolean isSundayFirstDay) { mRange = area; mTodayPosition = todayPosition; mFrom = from; mTo = to; mCurrentWeek = currentWeek; mIsSundayFirstDay = isSundayFirstDay; } } public static CalendarContext computeAreaAndTodayPosition(int initialArea, int initialTodayPosition) { // Compute min / max dates from now DateTime from = new DateTime().minusDays(initialArea - initialTodayPosition).dayOfWeek().withMinimumValue(); DateTime to = new DateTime().plusDays(initialTodayPosition).dayOfWeek().withMaximumValue(); boolean isSundayFirstDay = false; Calendar calendar = Calendar.getInstance(CompatUtils.getLocale(false)); if (calendar.getFirstDayOfWeek() == Calendar.SUNDAY) { isSundayFirstDay = true; from = from.minusDays(1); to = to.minusDays(1); } LogUtils.LOGD("XXXX", "from dt=" + from.toString()); LogUtils.LOGD("XXXX", "to dt=" + to.toString()); // Compute nb days area supported int daysRange = daysBetween(from, to).getDays() + 1; LogUtils.LOGD("XXXX", "daysRange=" + daysRange); // Compute today position int todayPosition = daysBetween(from, DateTime.now().withTimeAtStartOfDay()).getDays() + 1; LogUtils.LOGD("XXXX", "todayPosition=" + todayPosition); int currentWeek = DateTime.now().getWeekOfWeekyear() - from.getWeekOfWeekyear(); LogUtils.LOGD("XXXX", "currentWeek=" + currentWeek); return new CalendarContext(daysRange, todayPosition, from, to, currentWeek, isSundayFirstDay); } public CalendarPagerAdapter(FragmentManager mgr, int count, int todayPosition) { super(mgr); mDateTime = DateTime.now(); mCount = count; mTodayPosition = todayPosition; } @Override public int getCount() { return mCount; } public boolean isTodayPosition(int position) { return computeDifferenceDays(position) == 0; } public boolean isPastPosition(int position) { return computeDifferenceDays(position) < 0; } public boolean isFuturPosition(int position) { return computeDifferenceDays(position) > 0; } protected int computeDifferenceDays(int position) { return position - getCalendarTodayPosition(); } public long convertPositionToMs(int position) { return convertPositionToMs(mDateTime, position); } public long convertMinPositionToMs() { return convertPositionToMs(mDateTime, 0); } public long convertMaxPositionToMs() { return convertPositionToMs(mDateTime, mCount - 1); } public String convertPositionToDate(int position) { return TimeUnits.dateTimeToDateServer(new DateTime(convertPositionToMs(position))); } public long convertPositionToMs(DateTime datime, int position) { int dayNum = computeDifferenceDays(position); if (dayNum < 0) return datime.minusDays(Math.abs(dayNum)).getMillis(); else if (dayNum > 0) return datime.plusDays(Math.abs(dayNum)).getMillis(); else return datime.getMillis(); } public int convertMsToPosition(long millis) { DateTime dtReceived = new DateTime(millis).withTimeAtStartOfDay(); return convertDateTimeToPosition(dtReceived); } public int convertDateTimeToPosition(DateTime dtReceived) { DateTime now = DateTime.now().withTimeAtStartOfDay(); int nbDays = daysBetween(now, dtReceived).getDays(); return getCalendarTodayPosition() + nbDays; } public int getCalendarTodayPosition() { return mTodayPosition; } public void shiftWithOffset(WeekDatePicker weekDatePicker, TextView weekDatePickerDayTextView, DateTime currentSelectedDate, int offset) { if (offset < 0 && mTodayPosition > 0) mTodayPosition += offset; mDateTime = DateTime.now(); weekDatePicker.refreshTodayPosition(); weekDatePickerDayTextView.setText(TimeUnits.dateTimeToString( currentSelectedDate, true, true, true, true, true)); } } 表达式作为你选择中其他术语的平均值:

CASE

这是有效的,因为select avg(case when status then calculate_time end) as cal_time, count(case when status then 1 end) as completed, count(case when not status then 1 end) as failed, count(case when status is null then 1 end) as suspended from test; 函数与大多数其他聚合函数一样,忽略AVG个值。因此,NULL不为真的记录,其status值将被有效忽略,并且不会影响整体平均值。

其他注意事项:您可以直接在Postgres查询中使用布尔值,而无需将它们与calculate_time进行比较。也就是说,以下两个true表达式是等价的,第二个表达式更简洁:

CASE

答案 1 :(得分:2)

添加到@Tim的答案,因为Postgres 9.4你可以添加一个filter子句来聚合函数调用,这可以节省你编写自己的case的一些功能。表达式:

select
    avg(calculate_time) filter (where status) as cal_time,
    count(*) filter (where status) as completed,
    count(*) filter (where not status) as failed,
    count(*) filter (where status is null) as suspended
from test;