Sqlite неправильно упорядочивает даты в текстовом поле - PullRequest
0 голосов
/ 23 января 2019

У меня есть php-скрипт, который сохраняет в базе данных sqlite некоторые расписания.Это всегда работало, пока я не заметил почти две недели назад, что у sqlite было странное поведение.Я сохраняю даты в текстовом поле, и записи не могут быть упорядочены по дате.

Например, у меня есть несколько недавно добавленных дат для февраля, и если я выполню запрос, чтобы вернуть даты после 22 августа:

SELECT `date`, hex(`date`), substr(`date`, 1, 1), substr(`date`, 1) 
FROM Schedules WHERE `date` > '2019-08-22' order by `date`

Я получаю записи:

`date`              hex(`date`)                substr(`date`, 1, 1) substr(`date`, 1)
2019-08-22 13:00    323031392D30382D32322031333A3030    2           2019-08-22 13:00
2019-02-04 12:00    323031392D30322D30342031323A3030    2           2019-02-04 12:00
2019-02-18 12:00    323031392D30322D31382031323A3030    2           2019-02-18 12:00
2019-03-04 12:00    323031392D30332D30342031323A3030    2           2019-03-04 12:00

Первая запись верна, я включил ее для сравнения с неправильными.Я думал о том, чтобы иметь несколько символов до фактического числа, но из шестнадцатеричной колонки это не так.Я даже пытался запросить даты больше 3000, чтобы исключить дефис (возможно, у них был какой-то символ в юникоде), и он продолжал возвращать последние три записи предыдущих результатов.

Таблица определяется как:

CREATE TABLE `Schedules` (
  `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  `date` TEXT
);

Мой php-код для добавления записи:

class Schedule {
    public static function add_schedule($programmed_date, $programmed_time, $options) {
        $result = 0;
        date_default_timezone_set('Europe/Rome');
        $date = DateTime::createFromFormat('d/m/Y H:i', "$programmed_date $programmed_time");
        $now = new DateTime();
        if ($date < $now)
            return -1;
        $dbh = self::connect_to_database();
        $stmt = $dbh->prepare('INSERT INTO Schedules(`date`) VALUES (:date)');
        $stmt->bindValue(':date', $date->format('Y-m-d H:i'), SQLITE3_TEXT);
        try {
            $execution = $stmt->execute();
            if ($execution !== FALSE)
                $result = 1;
        }
        catch (Exception $ex) {}
        finally {
            $stmt->closeCursor();
        }
        $dbh = null;
        return $result;
    }

    private static function connect_to_database() {
        $db_path = Credentials::read_info('schedule')['db_path'];
        try {
            $dbh = new PDO('sqlite:'.$db_path);
            $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
            $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        }
        catch(PDOException $e) {
            echo 'Connection failed: '.$e->getMessage();
            exit;
        }
        return $dbh;
    }
}

На данный момент я не могу догадаться, что не так с кодом.Оператор sql должен возвращать только первую запись вместо четырех.Какие-нибудь мысли?Спасибо.

Сравнение SQLite DateTime привело меня к https://www.sqlite.org/lang_datefunc.html, и я нашел обходной путь, если я выполню запрос:

SELECT `date`, hex(`date`), substr(`date`, 1, 1), substr(`date`, 1) 
FROM Schedules WHERE datetime(`date`) > datetime('2019-08-22') order by `date`

Это работаетправильно вернул только запись за 22 августа.Однако я продолжаю задаваться вопросом, почему сравнение и порядок в обычном тексте приводят к ошибкам, когда здесь https://www.db -fiddle.com / f / ar9JxpaCo2wcQB1MobyaVv / 0 есть дамп, и вы ясно видите, что первый запрос, который я написалздесь возвращает другой (и правильный) результат.Если вы хотите попробовать напрямую в мою базу данных, вы можете скачать ее с здесь

Ответы [ 2 ]

0 голосов
/ 24 января 2019

Из ответа @DinoCoderSaurus у вас есть причина, почему ваши данные не ведут себя так, как должны.
Обходной путь, который я нашел:

WHERE date || ''  > '2019-08-22'

таким образом вы получите ожидаемый результат.
Конкатенация с пустой строкой преобразует date обратно в TEXT.

0 голосов
/ 24 января 2019

Ну, это было весело.Я скачал базу данных и играл в браузере БД для sqlite (только для чтения), пока не нашел что-то интересное.Это началось с толстого пальца date > '21' (он нашел 3 более ранних даты).Наконец, этот sql select *,typeof(date) from Schedules показал что-то

349|2019-08-22 13:00|text
374|2019-02-04 12:00|blob
375|2019-02-18 12:00|blob
376|2019-03-04 12:00|blob

Я создал репродукцию и обнаружил, что она будет вставлять дату в виде текста, если SQLITE3_TEXT удаляется из bindValue.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...