Android - SQLite, как получить дубликаты по двум столбцам? - PullRequest
0 голосов
/ 08 декабря 2018

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

card = player_card.card

Эта строка очень важна в запросе.Он хорошо работает в Access и других, но в Android он не работает.Приложение не отвечает и даже не выдает ошибку.

Что вы посоветуете?Заранее спасибо.

SELECT * FROM player_card
WHERE email 
In (SELECT email FROM player_card As Tmp
   GROUP BY email, card 
   HAVING COUNT(*) > 1 AND card = player_card.card)
   ORDER BY email;

Вот SQL Fiddle


Отредактировано в ответ на ответ от MikeT

Большое спасибо!Вы действительно помогли мне выбраться из бесконечного круга (для (;;)).Когда я помещаю ваш код в мое приложение ... результат идентичен - приложение не работает.Но почему?... Этот код SQL не работает с большими базами данных на Android - моя текущая база содержит 12 тысяч строк и 17 столбцов.Мобильное оборудование слишком слабое, чтобы работать с такими задачами.Когда я уменьшаю свою базу данных до 3 кб - код запускается около 1 минуты.В конце я понял две вещи:

Коды типа

card = player_card.card

нельзя использовать для больших баз данных Android;

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

Я хотел бы предложить выполнить запрос по частям, если вы беспокоитесь о больших базах данных.Вот несколько советов для вас.

  • Возможно, вы захотите иметь правильные индексы в вашей базе данных.Если адреса электронной почты уникальны, просто наложите уникальное ограничение на столбец адреса электронной почты.Это значительно снизит стоимость работы базы данных.Чтобы узнать больше об индексировании, пожалуйста, посмотрите учебник здесь.
  • Вы можете рассмотреть вопрос о результатах по частям.Во-первых, вы можете рассмотреть возможность сбора результатов второй части вашего общего запроса в курсоре, затем вы можете рассмотреть возможность итерации курсора, чтобы проверить, улучшилась ли производительность или нет.
  • Наконец, и самое главное, в случае длительных операций с запросами к базе данных, всегда пытайтесь выполнить запрос в AsyncTask, чтобы он не зависал в потоке пользовательского интерфейса.Я думаю, что трудоемкая работа с базой данных является причиной замораживания вашего приложения.Вот хорошее начало изучения того, как запускать ваши большие задачи в отдельном потоке, отличном от потока пользовательского интерфейса.

Надеюсь, это поможет!

0 голосов
/ 08 декабря 2018

У вас должно быть что-то не так в другом месте, код прекрасно работает на Android, согласно ( sql, скопированный в logIt метод ): -

public class DBHelper001 extends SQLiteOpenHelper {

    public static final String DBNAME = "db";
    public static final int DBVERSION =1;

    public static final String TABLE_PLAYER = "player_card";
    public static final String COL_PLAYERCARD_CARD = "card";
    public static final String COL_PLAYERCARD_EMAIL = "email";
    public static final String COL_PLAYERCARD_REGION = "region";
    public static final String COL_PLAYERCARD_Q = "quantidade";

    SQLiteDatabase mDB;

    public DBHelper001(Context context) {
        super(context, DBNAME, null, DBVERSION);
        mDB = this.getWritableDatabase(); //<<<<<<<<<< when helper is instantiated will force on Create and thus the logIt method to run.
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        mDB = db;
        db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_PLAYER + "(" +
                COL_PLAYERCARD_CARD + " TEXT, " +
                COL_PLAYERCARD_EMAIL + " TEXT, " +
                COL_PLAYERCARD_REGION + " TEXT," +
                COL_PLAYERCARD_Q + " INTEGER," +
                "PRIMARY KEY (" +
                COL_PLAYERCARD_EMAIL + "," +
                COL_PLAYERCARD_REGION + "," +
                COL_PLAYERCARD_CARD + ")" +
                ")"
        );
        //<<<<<<<<<< Add some test data
        insertPlayerCard("card1","a@x.id","EU",1);
        insertPlayerCard("card2","a@x.id","EU",1);
        insertPlayerCard("card1","a@x.id","US",1);
        //<<<<<<<<<< INVOKE THE LOGIT METHOD >>>>>>>>>>
        logIt();
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {

    }

    public long insertPlayerCard(String card, String email, String region, long quantitade) {
        ContentValues cv = new ContentValues();
        cv.put(COL_PLAYERCARD_CARD,card);
        cv.put(COL_PLAYERCARD_EMAIL,email);
        cv.put(COL_PLAYERCARD_REGION,region);
        cv.put(COL_PLAYERCARD_Q,quantitade);
        return mDB.insert(TABLE_PLAYER,null,cv);
    }

    //<<<<<<<<<< THE LOGIT METHOD RUNS QUERY AS COPIED AND REPORTS ROWS EXTRACTED >>>>>>>>>>
    public void logIt() {
        String sql = "SELECT * FROM player_card " +
                "WHERE email " +
                "In (SELECT email FROM player_card As Tmp " +
                "   GROUP BY email, card " +
                "   HAVING COUNT(*) > 1 AND card = player_card.card) " +
                "   ORDER BY email;";
        Cursor csr = mDB.rawQuery(sql,null);
        Log.d("RESULT","Number of rows extracted = " + String.valueOf(csr.getCount()));
        csr.close();
    }
}

Простое создание экземпляра и экземпляр (если база данных не существует) запускает метод logIt, который возвращает: -

12-08 05:31:50.247 2049-2049/? D/RESULT: Number of rows extracted = 2

Дополнительное повторное редактирование в оригиналевопрос

Дело не в том, что вы не можете сделать это на Android, вы можете, НО это требует времени.

Короче говоря, база данных, приведенная выше, была загружена 20997 строками, а запрос применен 3 раза: -

  • 1-й для компенсации проблем с кэшированием / первым запуском
  • 2-й - 1-й тестовый запуск.
  • 3-й после создания индекса для столбца карты.

Каждый запуск работал, НО каждый занимал 20 минут (на эмулируемом устройстве, которое, я считаю, может быть быстрее, чем некоторые реальные устройства).

  • Обратите внимание, что все выполняются в потоке, чтобыизбегайте ANR (Android не отвечает, возможно, это ваша проблема)

результаты loged as: -

12-09 02:02:33.325 3702-3715/so53646027.so53646027 D/THREADREPORT: Started at (getting row count)2018-12-09 00:57:35.609+0000
        Number of Rows in player_card is 20997 at 2018-12-09 00:57:35.633+0000
        Finished Run to ignore chacheing effects at 2018-12-09 01:19:04.769+0000
        Finished Test Run without Index (started creating index on card column) at 2018-12-09 01:40:54.147+0000
        Finished Creating Index at; Starting Test Run with Index at 2018-12-09 01:40:54.223+0000
        Finished 2nd Test Run (now dropping index) at 2018-12-09 02:02:33.321+0000
        Finished at 2018-12-09 02:02:33.328+0000

Затем я скопировал базу данных и выполнил тот же самый запрос (один раз) в Navicat (здесь не самый медленный ПК в мире), для выполнения которого потребовалась доля менее 6 минут.

Из других тестов ясно, что card = player_card.card является основной проблемой.Перемещение его в предложение WHERE значительно сокращает время запроса до того времени, которое я считаю приемлемым / приемлемым, например: -

12-09 06:09:54.501 4845-4858/so53646027.so53646027 D/THREADREPORT: Started at (getting row count)2018-12-09 06:09:50.474+0000
        Number of Rows in player_card is 20997 at 2018-12-09 06:09:50.477+0000
        Finished Run to ignore chacheing effects at 2018-12-09 06:09:51.858+0000
        Finished Test Run without Index (started creating index on card column) at 2018-12-09 06:09:52.969+0000
        Finished Creating Index at; Starting Test Run with Index at 2018-12-09 06:09:53.048+0000
        Finished 2nd Test Run (now dropping index) at 2018-12-09 06:09:54.499+0000
        Finished at 2018-12-09 06:09:54.505+0000

Примерно 1,5 секунды, с теми же результатами, что и при полной регистрации: -

12-09 06:09:51.853 4845-4858/so53646027.so53646027 D/RESULT: Number of rows extracted = 7368
12-09 06:09:51.853 4845-4858/so53646027.so53646027 D/THREADREPORT: Finished Run to ignore cacheing at 2018-12-09 06:09:51.857+0000
12-09 06:09:52.965 4845-4858/so53646027.so53646027 D/RESULT: Number of rows extracted = 7368
12-09 06:09:52.965 4845-4858/so53646027.so53646027 D/THREADREPORT: Finished 1st Test RUN (not indexed, now building Index) at 2018-12-09 06:09:52.969+0000
12-09 06:09:53.045 4845-4858/so53646027.so53646027 D/THREADREPORT: Index created (starting 2nd Test Run) at 2018-12-09 06:09:53.048+0000
12-09 06:09:54.493 4845-4858/so53646027.so53646027 D/RESULT: Number of rows extracted = 7368
12-09 06:09:54.493 4845-4858/so53646027.so53646027 D/THREADREPORT: Finished 2nd Test RUN (dropping Index) at 2018-12-09 06:09:54.499+0000
12-09 06:09:54.501 4845-4858/so53646027.so53646027 D/THREADREPORT: Finished at 2018-12-09 06:09:54.505+0000
12-09 06:09:54.501 4845-4858/so53646027.so53646027 D/THREADREPORT: Started at (getting row count)2018-12-09 06:09:50.474+0000
        Number of Rows in player_card is 20997 at 2018-12-09 06:09:50.477+0000
        Finished Run to ignore chacheing effects at 2018-12-09 06:09:51.858+0000
        Finished Test Run without Index (started creating index on card column) at 2018-12-09 06:09:52.969+0000
        Finished Creating Index at; Starting Test Run with Index at 2018-12-09 06:09:53.048+0000
        Finished 2nd Test Run (now dropping index) at 2018-12-09 06:09:54.499+0000
        Finished at 2018-12-09 06:09:54.505+0000

т. Е. На протяжении всего времени я последовательно возвращал 7368 строк.

Поэтому я считаю, что вы можете использовать / конвертировать: -

public void logIt() {
    String sql = "SELECT * FROM player_card " +
            "WHERE email " +
            "In (SELECT email FROM player_card As Tmp " +
            "   WHERE card = player_card.card " +
            "   GROUP BY email, card " +
            "   HAVING COUNT(*) > 1) " +
            "   ORDER BY email;";
    Cursor csr = mDB.rawQuery(sql,null);
    Log.d("RESULT","Number of rows extracted = " + String.valueOf(csr.getCount()));
    csr.close();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...