按月计算的活跃成员数量

时间:2017-10-01 14:00:09

标签: mysql

寻找一个优雅的解决方案...我发现我所做的任何事情都非常难看......我只是想为每个月绘制一个活跃的用户数(在他们的开始/结束日期内)。当然,我需要一个0的计数,其中月份在该报告日期范围内没有活跃用户...

public class graph extends AppCompatActivity {
private  static  final String TAG = "graph";
PointsGraphSeries<DataPoint> xySeries;
private Button btnAddPt;
private EditText mX,mY;
GraphView mScatterPlot;
private ArrayList <XYValues> xyValuesArray;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_graph);
    btnAddPt = (Button) findViewById(R.id.BtnAddPt);
    mX = (EditText) findViewById(R.id.numX);
    mY = (EditText) findViewById(R.id.numY);
    mScatterPlot = (GraphView) findViewById(R.id.scatterPlot);
    xyValuesArray = new ArrayList<>();
    init();
}
private  void init() {
    xySeries = new PointsGraphSeries<>();
    btnAddPt.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (!mX.getText().toString().equals("") && !mY.getText().toString().equals("")) {
                double x = Double.parseDouble(mX.getText().toString());
                double y = Double.parseDouble(mY.getText().toString());
                Log.d(TAG, "onClick: Adding a new point. (x,y)(" + x + "," + y + ")");
                xyValuesArray.add(new XYValues(x, y));
                init();
            } else


            {
                toastMessage("You must fill both fields");
            }
        }


    });

    if (xyValuesArray.size() != 0) {
        createScatterPlot();

    } else {
        Log.d(TAG, "onCreate: No data to plot");

    }
}
private void createScatterPlot(){
    Log.d(TAG, "createScatterPlot:Creating scatter plot.");
    xyValuesArray = sortArray(xyValuesArray);
    for (int i =0; i<xyValuesArray.size();i++){
        try{
            double x = xyValuesArray.get(i).getX();
            double y = xyValuesArray.get(i).getY();
            xySeries.appendData(new DataPoint(x,y),true,1000);

        }catch (IllegalArgumentException e){


            Log.e(TAG, "createScatterPlot:IllegalArgumentException: "+e.getMessage());
        }
    }
    xySeries.setShape(PointsGraphSeries.Shape.POINT);
    xySeries.setColor(Color.BLUE);
    xySeries.setSize(20f);

    mScatterPlot.getViewport().setScalable(true);
    mScatterPlot.getViewport().setScalableY(true);
    mScatterPlot.getViewport().setScrollable(true);
    mScatterPlot.getViewport().setScrollableY(true);

    mScatterPlot.getViewport().setYAxisBoundsManual(true);
    mScatterPlot.getViewport().setMaxY(250);
    mScatterPlot.getViewport().setMinY(0);

    mScatterPlot.getViewport().setXAxisBoundsManual(true);
    mScatterPlot.getViewport().setMaxX(3000);
    mScatterPlot.getViewport().setMinX(0);

    mScatterPlot.addSeries(xySeries);
}

private  ArrayList<XYValues> sortArray(ArrayList<XYValues>array){
    int factor = Integer.parseInt(String.valueOf(Math.round(Math.pow(array.size(),2))));
    int m = array.size() - 1;
    int count =0;
    Log.d(TAG,"sortArray:Sorting XYarray");
    while (true){
        m--;
        if(m<=0){
            m=array.size()-1;
        }
        Log.d(TAG,"SortArray: m =" +m);
        try{
            double tempY = array.get(m-1).getY();
            double tempX = array.get(m-1).getX();
            if (tempX>array.get(m).getX()){
                array.get(m-1).setY(array.get(m).getY());
                array.get(m).setY(tempY);
                array.get(m-1).setX(array.get(m).getX());
                array.get(m).setX(tempX);
            }
            else if (tempX ==array.get(m).getX()){
                count++;
                Log.d(TAG,"sortArray: count = "+count);

            }
            else if (array.get(m).getX()>array.get(m-1).getX()){
                count++;
                Log.d(TAG,"sortArray: count = "+count);
            }
            if (count == factor){
                break;
            }
        }catch (ArrayIndexOutOfBoundsException e){
            Log.e(TAG,"sortArray: ArrayIndexOutBoundsException. Need more than 1 data to create plot = "+e.getMessage());
            break;
        }
    }
    return array;
}
private void toastMessage (String message){
    Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}

}

所以我需要一个月份的活跃成员报告...也就是说,给定一个范围的给定月份中有多少成员活跃的数量...所以预期结果:

TABLE MEMBERSHIPS
Name, Start_date, End_date
Joe,  2017/02/01, 2017/04/01
Bob,  2017/03/01, 2017/05/01
Moe,  2017/03/01, 2017/05/01
Lou,  2017/04/01, 2017/05/01

我确信这是一个常见的用例......只是找不到任何好的东西......

谢谢,

1 个答案:

答案 0 :(得分:1)

这里的问题是缺少创建报告所需的部分数据。数据库应该如何知道您希望包含月份01,尽管该月没有数据?

解决此问题的一种简单方法是创建一个包含报告应包含的所有月份的表。为了进一步简化事情,而不是年份和月份本身,只需将相应月份中的任意日期写入该表中。

Table ReportMonths:
ReportMonth datetime
2017-01-15
2017-02-15
2017-03-15
2017-14-15
2017-05-15
2017-06-15

使用新表创建报告:

SELECT
  ReportMonths.ReportMonth,
  COUNT(*)
FROM
  ReportMonths, MEMBERSHIPS
WHERE
  (MEMBERSHIPS.Start_date <= ReportMonths.ReportMonth) AND
  (MEMBERSHIPS.End_date > ReportMonths.ReportMonth)
GROUP BY
  ReportMonths.ReportMonth;

<强>声明

1)我现在手头没有MySQL,所以我无法测试代码。如果有语法错误,请原谅我。不过,它应该会给你一个如何解决问题的一般信息。

2)如果你有数百万行,那么这个解决方案可能会很慢,或者可能会让MySQL感到震惊,因为它必须首先构建两个表的交叉产品。如果是这种情况,我们可以构建一个更复杂的查询,其行为更好。如果您有兴趣,请告诉我们......

免责声明

上述解决方案将返回相关月份作为日期。如果您不想要,请SELECT YEAR(ReportMonths.ReportMonth), MONTH(ReportMonths.ReportMonth), ...代替SELECT ReportMonths.ReportMonth, ...

如果您不想使用第二个表,那么我担心您将不得不编写一个存储过程或后端应用程序,它会循环遍历每年和每个月,并在每个循环中选择计数在当前年/月之前和之后开始的行,然后将该计数写入某处,可能是另一个表或数组,以便进一步处理。

优点是数据库不必在两个表之间构建交叉产品;缺点是这不是一个查询解决方案。