简体   繁体   中英

How to get data between two dates from sqlite database which is in dd/mm/yyyy format

I'm building an app which select rows between to dates which is in dd/mm/yyyy format and count the row having status pending, signup and rejected. I have done some work on it, but its not working. I stored date as TEXT in database. I pasted code below.

public void showMonthlyPopUp(View view) {
    weeklyDialog.setContentView(R.layout.pop_up_all_list);
    TextView nameTextView = weeklyDialog.findViewById(R.id.textView);
    nameTextView.setText("MONTHLY");
    TextView pendingTextView = weeklyDialog.findViewById(R.id.textView6);
    TextView signUpTextView = weeklyDialog.findViewById(R.id.textView3);
    TextView rejectedTextView = weeklyDialog.findViewById(R.id.textView7);
    Button shareButton = weeklyDialog.findViewById(R.id.button_share);

    String[] projection = {
            InfoContract.InfoEntry._ID,
            InfoContract.InfoEntry.COLUMN_STATUS,
            InfoContract.InfoEntry.COLUMN_DATE
    };

    Calendar calendar = Calendar.getInstance();
    String strDate = calendar.get(Calendar.MONTH) + "/" + calendar.get(Calendar.YEAR);
    int dayInt = calendar.get(Calendar.DAY_OF_MONTH);

    String[] selectionArgs = new String[dayInt];
    for (int i = 1; i <= dayInt; i++) {
        selectionArgs[i - 1] = i + "/" + strDate;
    }

    String selection = InfoContract.InfoEntry.COLUMN_DATE + " =?";
    for (int i = 1; i < dayInt; i++) {
        selection += " OR " + InfoContract.InfoEntry.COLUMN_DATE + " =?";
    }
    Cursor cursor = this.getContentResolver().query(InfoContract.InfoEntry.CONTENT_URI, projection, selection, selectionArgs, null);
    int pending = 0;
    int signUp = 0;
    int rejected = 0;
    while (cursor.moveToNext()) {
        int statusColumnIndex = cursor.getColumnIndex(InfoContract.InfoEntry.COLUMN_STATUS);
        int status = cursor.getInt(statusColumnIndex);
        if (status == InfoContract.InfoEntry.STATUS_SIGN_UP) signUp = signUp + 1;
        else if (status == InfoContract.InfoEntry.STATUS_REJECTED) rejected++;
        else pending++;
    }
    cursor.close();
    pendingTextView.setText("" + pending);
    signUpTextView.setText("" + signUp);
    rejectedTextView.setText("" + rejected);
    weeklyDialog.show();
    final int finalPending = pending;
    final int finalSignUp = signUp;
    final int finalRejected = rejected;
    shareButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            shareData(finalPending, finalSignUp, finalRejected, "Monthly Details: ");

        }
    });

}

Life will be quite hard using the format dd/mm/yyyy as it's not readily usable by the most obvious SELECT using a BETWEEN clause as part of the WHERE clause, even harder when dd/mm/yyyy is often with single characters for values that are less than 10 (eg 1/1/2019 instead of 10/10/2019).

Consider mytable created and loaded using :-

DROP TABLE IF EXISTS mytable;
CREATE TABLE IF NOT EXISTS mytable (mydatecolumn TEXT, myothercolumn TEXT DEFAULT 'BLAH');
INSERT INTO mytable (mydatecolumn) 
    VALUES 
        ('01/01/2019'),('1/1/2019'),('01/1/2019'),('1/01/2019'),
        ('10/1/2019'),('10/10/2019'),('1/10/2019'),('01/02/2019'),
        ('1/3/2019'),('01/1/2019'),('14/01/2019'),('10/1/2019'),
        ('10/10/2020'),('1/10/2018')
; 

Which looks like :-

在此处输入图片说明

The query to transpose values and to then select a date range could be :-

-- An example that would hanlde dd/mm/yyyy where dd and mm could be either 1 or 2 characters
WITH 

    -- First CTE gets the day and the rest of the date
    ctedaypart AS (
        SELECT 
            rowid AS daypartid, 
            substr(mydatecolumn,1,instr(mydatecolumn,'/')-1) AS day_part, 
            substr(mydatecolumn,instr(mydatecolumn,'/')+1) AS rest_after_day 
        FROM mytable
    ),

    -- Second CTE gets the month and the rest of the date
    ctemonthpart AS (
        SELECT 
            daypartid AS monthpartid,
            substr(rest_after_day,1,instr(rest_after_day,'/')-1) AS month_part, 
            substr(rest_after_day,instr(rest_after_day,'/')+1) AS year 
        FROM ctedaypart
    ),

    -- Third CTE expands the day and month the have a leading 0 id less than 10 and joins the parts to form YYYY-MM-DD 
    expandedparts AS (
        SELECT
            *,
            mytable.rowid AS expandedpartsid,
          year||'-'||
            CASE WHEN length(month_part) = 1 THEN '0'||month_part ELSE month_part END ||'-'||
            CASE WHEN length(day_part) = 1 THEN '0'||day_part ELSE day_part END AS date_in_sqlite_format
        FROM mytable JOIN ctedaypart ON mytable.rowid = daypartid  JOIN ctemonthpart ON daypartid = monthpartid)

SELECT mytable.* FROM mytable JOIN expandedparts ON mytable.rowid = expandedpartsid WHERE (date_in_sqlite_format) BETWEEN ('2019-01-01') AND ('2019-03-31');

The above results in 10 of the 14 rows being selected as per :-

在此处输入图片说明


However

If the date is saved in the database in a recognised format eg YYYY-MM-DD then the above could simply be :-

SELECT * FROM mytable WHERE (mydatecolumn) BETWEEN ('2019-01-01') AND ('2019-03-31');

As such it is suggested that you adopt the use of a recognised format for dates when interacting with the database :-

 Time Strings A time string can be in any of the following formats: YYYY-MM-DD YYYY-MM-DD HH:MM YYYY-MM-DD HH:MM:SS YYYY-MM-DD HH:MM:SS.SSS YYYY-MM-DDTHH:MM YYYY-MM-DDTHH:MM:SS YYYY-MM-DDTHH:MM:SS.SSS HH:MM HH:MM:SS HH:MM:SS.SSS now DDDDDDDDDD 

SQL As Understood By SQLite - Date And Time Functions

The alternative is to use or adapt the complex query above or use one that is similar.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM