![]() |
|
|||
WebMoney: WMZ Z294115950220 WMR R409981405661 WME E134003968233 |
Visa 4274 3200 2453 6495 |
![]()
Small. Fast. Reliable.
Choose any three. Значения строк
1. Определения"Значение" это единственное число, последовательность, BLOB или NULL. Иногда полностью определенное имя "скалярное значение" используется, чтобы подчеркнуть, что только единственное количество включается. "Значение строки" является упорядоченным списком двух или больше скалярных величин. Другими словами, "значение строки" является вектором или кортежем. "Размер" значения строки это количество скалярных величин, которые содержит значение строки. Размер значения строки всегда по крайней мере 2. Значение строки с отдельным столбцом это просто скалярная величина. Значение строки без колонок это синтаксическая ошибка. 2. СинтаксисSQLite SQLite позволяет значениям строки быть выраженными двумя способами:
SQLite может использовать значения строки в двух контекстах:
Синтаксис для значений строки и обстоятельств, при которых могут использоваться значения строки, иллюстрирован в примерах ниже. 2.1. Сравнения значения строкиДва значения строки сравнены, смотря на учредительные скалярные величины слева направо. NULL значит "unknown". Полный результат сравнения NULL, если возможно сделать результат true или false, заменяя альтернативными значениями вместо учредительного NULL. Следующий запрос демонстрирует некоторые сравнения значения строки: SELECT (1,2,3) = (1,2,3), -- 1 (1,2,3) = (1,NULL,3), -- NULL (1,2,3) = (1,NULL,4), -- 0 (1,2,3) < (2,3,4), -- 1 (1,2,3) < (1,2,4), -- 1 (1,2,3) < (1,3,NULL), -- 1 (1,2,3) < (1,2,NULL), -- NULL (1,3,5) < (1,2,NULL), -- 0 (1,2,NULL) IS (1,2,NULL); -- 1 Результат "(1,2,3)=(1,NULL,3)" это NULL, потому что результат мог бы быть верным, если бы мы заменили NULL>2 или ложным, если мы заменили NULL>9. Результат "(1,2,3)=(1,NULL,4)" не NULL, потому что нет никаких замен учредительного NULL, которые сделают выражение верным, так как 3 никогда не будет равняться 4 в третьей колонке. Любое из значений строки в предыдущем примере могло быть заменено подзапросом, который возвращает три колонки, и тот же самый ответ был бы получен. Например: CREATE TABLE t1(a,b,c); INSERT INTO t1(a,b,c) VALUES(1,2,3); SELECT (1,2,3)=(SELECT * FROM t1); -- 1 2.2. Значение строки и оператор INДля значения строки у оператора IN, левая сторона (после этого "LHS") может быть списком значений или подзапросом с многочисленными колонками. Но правая сторона (после этого "RHS") должна быть выражением подзапроса. CREATE TABLE t2(x,y,z); INSERT INTO t2(x,y,z) VALUES(1,2,3),(2,3,4),(1,NULL,5); SELECT (1,2,3) IN (SELECT * FROM t2), -- 1 (7,8,9) IN (SELECT * FROM t2), -- 0 (1,3,5) IN (SELECT * FROM t2); -- NULL 2.3. Значения строки в запросах UPDATEЗначения строки могут также использоваться в пункте SET запроса UPDATE. LHS должен быть списком имен столбцов. RHS может быть любым значением строки. Например: UPDATE tab3 SET (a,b,c) = (SELECT x,y,z FROM tab4 WHERE tab4.w=tab3.d) WHERE tab3.e BETWEEN 55 AND 66; 3. Использование в качестве примера значений строки3.1. Прокрутка запросов окнаПредположим, что применение хочет показать список контактов в алфавитном порядке lastname, firstname, в окне, которое может показать только 7 контактов за один раз. Инициализируйте окно к первым 7 записям: SELECT * FROM contacts ORDER BY lastname, firstname LIMIT 7; Когда пользователь прокручивает вниз, применение должно найти второй набор из 7 записей. Один способ сделать это: использовать пункт OFFSET: SELECT * FROM contacts ORDER BY lastname, firstname LIMIT 7 OFFSET 7; OFFSET дает правильный ответ. Однако, OFFSET требует времени, пропорционального значению. Что действительно происходит с "LIMIT x, OFFSET y" это то, что SQLite вычисляет запрос как "LIMIT x+y" и отказывается от первых значений y, не возвращая их к применению. Таким образом, поскольку окно прокручивают вниз к основанию длинного списка, и значение y становится больше, то большие последовательные вычисления смещения занимают все больше времени. Более эффективный подход должен помнить последний вход, в настоящее время показываемый, и затем использовать сравнение значения строки в операторе Where: SELECT * FROM contacts WHERE (lastname,firstname) > (?1,?2) ORDER BY lastname, firstname LIMIT 7; Если lastname и firstname в нижней строке предыдущего экрана связаны с ?1 и ?2, тогда запрос выше вычисляет следующие 7 строк. Это намного более эффективно, чем OFFSET. 3.2. Сравнение дат, сохраненных как отдельные областиОбычный способ сохранить дату в таблице базы данных как единственное поле или как метку времени Unix, юлианское дневное число или как последовательность дат ISO 8601. Но некоторое применение хранит даты как три отдельных области для года, месяца и дня. CREATE TABLE info(year INT, -- 4 digit year month INT, -- 1 through 12 day INT, -- 1 through 31 other_stuff BLOB); Когда даты сохранены так, сравнения значения строки обеспечивают удобный способ сравнить даты: SELECT * FROM info WHERE (year,month,day) BETWEEN (2015,9,12) AND (2016,9,12); 3.3. Поиск многостолбцовых ключейПредположим, что мы хотим знать номер заказа, номер продуктов и количество для любого пункта, в котором номер продуктов и количество соответствуют номеру продуктов и количеству любого пункта в номере заказа 365: SELECT ordid, prodid, qty FROM item WHERE (prodid, qty) IN (SELECT prodid, qty FROM item WHERE ordid = 365); Запрос выше мог быть переписан как соединение и без использования значений строки: SELECT t1.ordid, t1.prodid, t1.qty FROM item AS t1, item AS t2 WHERE t1.prodid=t2.prodid AND t1.qty=t2.qty AND t2.ordid=365; Поскольку тот же самый запрос мог быть написан без использования значений строки, значения строки не обеспечивают новые возможности. Однако, многие разработчики говорят, что формат значения строки легче прочитать. Даже в форме JOIN, запрос может быть сделан более ясным с помощью значений строки: SELECT t1.ordid, t1.prodid, t1.qty FROM item AS t1, item AS t2 WHERE (t1.prodid,t1.qty) = (t2.prodid,t2.qty) AND t2.ordid=365; Этот более поздний запрос производит точно тот же самый bytecode, как предыдущая скалярная формулировка, но синтаксис использования легче читать. 3.4. Обновите многочисленные колонки таблицы на основе запросаНотация значения строки полезна для обновления двух или больше колонок таблицы от результата единого запроса. Пример этого находится в полнотекстовой функции поиска Fossil version control system. В Fossil полнотекстовая система поиска документов, которые участвуют в полнотекстовом поиске (страницы Wiki, билеты, регистрации, файлы документации и т. д.) прослежена таблицей, названной "ftsdocs" (full text search documents). Когда новые документы добавляются к хранилищу, они не внесены в указатель сразу же. Индексация отсрочена, пока нет поискового запроса. Таблица ftsdocs содержит область "idxed", которая верна, если документ был внесен в указатель и ложная, если нет. Когда поисковый запрос происходит, и документы внесены в указатель впервые, таблица ftsdocs должна быть обновлена, установив колонку idxed в true, а также заполнив несколько других колонок информацией, подходящей для поиска. Другая информация получена из соединения: UPDATE ftsdocs SET idxed=1, name=NULL, (label,url,mtime) = (SELECT printf('Check-in [%%.16s] on %%s',blob.uuid, datetime(event.mtime)), printf('/timeline?y=ci&c=%%.20s',blob.uuid), event.mtime FROM event, blob WHERE event.objid=ftsdocs.rid AND blob.rid=ftsdocs.rid) WHERE ftsdocs.type='c' AND NOT ftsdocs.idxed См. исходный текст для подробностей. Другие примеры: здесь и здесь. Пять из девяти колонок в таблице ftsdocs обновляются. Две из измененных колонок, "idxed" и "name", могут быть обновлены независимо от запроса. Но эти три колонки "label", "url" и "mtime", все требуют запроса соединения против таблиц "event" и "blob". Без значений строки эквивалентный UPDATE потребовал бы, чтобы соединение было повторено три раза, однажды для каждой колонки, которая будет обновлена. 3.5. Ясность представленияИногда использование значений строки просто делает более легким SQL. Рассмотрите следующие два запроса UPDATE: UPDATE tab1 SET (a,b)=(b,a); UPDATE tab1 SET a=b, b=a; Оба UPDATE делают точно то же самое. Они производят идентичный bytecode. Но первая форма, форма значения строки, кажется, делает более ясным, что намерение запроса состоит в том, чтобы обменять значения в колонках A и B. Или рассмотрите эти идентичные запросы: SELECT * FROM tab1 WHERE a=?1 AND b=?2; SELECT * FROM tab1 WHERE (a,b)=(?1,?2); Еще раз SQL-операторы производят идентичный bytecode и таким образом делают точно ту же самую работу точно таким же образом. Но вторая форма сделана легче для чтения, собрав в группу параметры запроса в единственное значение строки вместо того, чтобы рассеять по оператору Where. 4. Обратная совместимостьЗначения строки были добавлены к SQLite version 3.15.0 (2016-10-14). Попытки использовать значения строки в предыдущих версиях SQLite произведут синтаксические ошибки. |