Как получить данные между двумя датами из базы данных sqlite в формате дд / мм / гггг - PullRequest
0 голосов
/ 05 июля 2019

Я создаю приложение, которое выбирает строки между датами в формате дд / мм / гггг и подсчитывает строки, имеющие статус ожидающий, подписанный и отклоненный. Я сделал некоторую работу над этим, но он не работает. Я сохранил дату как ТЕКСТ в базе данных. Я вставил код ниже.

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: ");

        }
    });

}

1 Ответ

2 голосов
/ 05 июля 2019

Жизнь будет довольно тяжелой, если использовать формат дд / мм / гггг, поскольку ее нелегко использовать с помощью наиболее очевидного оператора SELECT, использующего предложение BETWEEN в качестве части предложения WHERE, еще сложнее, когда дд / мм / гггг часто содержат одиночные символы. для значений, которые меньше 10 (например, 01.01.2009 вместо 10/10/2019).

Рассмотрим mytable , созданный и загруженный с помощью: -

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')
; 

Что выглядит как: -

enter image description here

Запрос на транспонирование значений и выбор диапазона дат может быть: -

-- 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');

Вышеуказанное приводит к 10 из 14 строк, выбранных согласно: -

enter image description here


Однако

Если дата сохраняется в базе данных в распознанном формате, например YYYY-MM-DD, тогда вышеприведенное может быть просто: -

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

В связи с этим предлагается использовать признанный формат для дат при взаимодействии с базой данных : -

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 как понял SQLite - функции даты и времени

Альтернативой является использование или адаптация сложного запроса выше или использование аналогичного запроса.

...