Запрос к базе данных из StarBasic возвращает неожиданный результат

Автор ost, 8 февраля 2017, 18:12

0 Пользователи и 1 гость просматривают эту тему.

ost

Доброго
Объясните, пожалуйста, причину странного результата команды SELECT в случае если запрашивается выборка по несуществующему полю.

Странность заключается в том, что при выполнении

...
ResultSet = Statement.executeQuery("SELECT ""Absent"" FROM ""B""")

в случае отсутствия в таблице "B" поля "Absent" вместо ожидаемой ошибки а-ля "no such column: Absent"
получаю таблицу-выборку с числом записей равным числу записей в таблице "B" и одной колонкой-полем. При этом значение полей всех записей равно "Absent".
О_о



mikekaganski

Ну, специалистов по абсенту я здесь не помню, только по коньяку... :)

А если серьёзно - Вы же берёте строку в кавычки - это уже не название поля, а строковое выражение. Ну, могло быть так (если числовое поле Z есть):

SELECT 1 + Z FROM "B" - выдаст число записей, соответствующее размеру таблицы - а числа не как в ячейке, логично?
SELECT 1 FROM "B" - выдаст число записей, соответствующее размеру таблицы - а числа все 1;
SELECT "Absent" FROM "B" - аналогично
С уважением,
Михаил Каганский

economist

Кто-ж так абсент выбирает? Нужно без кавычек :-)

Вот, кстати, как можно писать код, если СУБД к Base выбрана не HSQL, а нормальная, тот же SQLite - то про неприязнь к кириллице и кавычки можно забыть:    


ResultSet = Statement.executeQuery("SELECT ФИО, АДРЕС, ОКЛАД, * FROM СОТРУДНИКИ WHERE ОКЛАД>100000 AND 2 LIKE '%Москва%'")


Ну красиво же!
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

Спасибо за ответы. Продолжим с абсентом, не злоупотребляя. =)
Цитата: economist от  8 февраля 2017, 20:22Вот, кстати, как можно писать код, если СУБД к Base выбрана не HSQL, а нормальная, тот же SQLite
Да, база используется SQLite. Тем не менее запрос вида:

ResultSet = Statement.executeQuery("SELECT Absent FROM B")

при условии, что поле "Absent" отсутствует в таблице "B" результат не изменяет. На выходе имеем точно такую же таблицу-выборку:
1. Число строк=числу записей в таблице базы данных.
2. Количество полей=1.
3. Значение всех полей="Absent".

Где ошибаюсь не пойму. Может, ошибка в сопутствующем коде?
Прилагаю файлик с макросом. Ткните, пожалуйста, в косячное место.

rami

Цитата: ost от  9 февраля 2017, 08:42Где ошибаюсь не пойму. Может, ошибка в сопутствующем коде?
Прилагаю файлик с макросом. Ткните, пожалуйста, в косячное место.
Код вроде без ошибок. У меня нет SQLite, а в HSQL нормально, ругается если нет таблицы или поля. Нужно смотреть документацию SQLite, возможно это её особенность или глюк.

Какой результат вы хотите получить если запрашиваете несуществующие данные ???

economist

Есть в Base одна пакостная вещь - свой парсер SQL-выражений, порождающий недоумение и злобу.
В GUI BASE - это та самая таинственная кнопка в Query Designe, на которой написано три буквы: SQL. Ненажатая - она коверкает запрос так, что ODBC-драйверы запрос не понимают, или работают не так как надо. Это параметр EscapeProcessing = False  

Не проверял, но думаю нужно так:

Statement = bd.createStatement()
Statement.EscapeProcessing = False 'вот оно чё, Михалыч!


В BASIC-коде лучше все данные из БД закачивать в динамический объект типа RecordSet, который по сути предоставляет самый быстрый и бесконфликтный способ подвыборки, изменения и удаления данных в базе.
Сейчас могу лишь копипастнуть свой код:


RowSet = createUnoService("com.sun.star.sdb.RowSet") ' создаем
RowSet.DataSourceName = "YourDataBase" ' указываем зарегистрированную базу данных, без *.odb!
RowSet.CommandType = com.sun.star.sdb.CommandType.COMMAND ' вызываем команду
RowSet.EscapeProcessing=FALSE
SQLSTR="SELECT * FROM СОТР"
RowSet.Command = SQLSTR 'задаем команду для набора строк
'On Error Goto ErrSQL
RowSet.execute() ' выполняем
rowSet.Last 'мотнули курсор к концу, чтобы узнать сколько строк
RowEND=(rowSet.RowCount()-1)
rowSet.First ' вернулись к первой записи. Теперь можно циклом перебрать  

Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

economist

Если в SQLite-базе есть, как у меня, кириллические таблицы и поля - нужно еще настроить ODBC/unixODBC-драйвер. Кириллица, кстати, работает без глюков. С её помощью я научил писать запросы пару десятков человек, на английском процесс не шел даже под угрозой увольнения (это к вопросу о поддержке кириллицы везде, где можно и почему нельзя в ней отказывать простым людям). 
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

Цитата: rami от  9 февраля 2017, 09:18Какой результат вы хотите получить
Ошибку выполнения или любой другой результат, который можно было бы отловить в макросе и соотнести с ошибкой.

economist

Сейчас еще раз перечитал ветку (не спал ночь из-за урагана, сорри) и понял что

ResultSet = Statement.executeQuery("SELECT Absent FROM B")


- ведет себя так потому что Absent воспринимается чем-то как литерал. Это чем-то может быть как движок Base, так и конкретный ODBC-драйвер. Голая SQLite так себя не ведет.

Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

economist

Из настроек ODBC-драйвера для Windows - нужно включить лишь OEMCP Translation.
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

economist

Для будущих поколений и в защиту великого и могучего русского языка в запросах: "русско"-фобия играет злую шутку с её апологетами. Абсент хоть и не входит в SQL reserved words, но может войти в любую секунду. Поэтому собирая запрос по кускам, проверяйте - не вошло ли имя таблицы/поля/псевдонима в этот список:


reservedSQL = Array("ACCESSIBLE", "ADD", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", "ASENSITIVE", "BEFORE", _
"BETWEEN", "BIGINT", "BINARY", "BLOB", "BOTH", "BY", "CALL", "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", "CHECK", "COLLATE", _
"COLUMN", "CONDITION", "CONSTRAINT", "CONTINUE", "CONVERT", "CREATE", "CROSS", "CURRENT_DATE", "CURRENT_TIME", _
"CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "DATABASE", "DATABASES", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", _
"DAY_SECOND", "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", "DETERMINISTIC", "DISTINCT", _
"DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", "ELSE", "ELSEIF", "ENCLOSED", "ESCAPED", "EXISTS", "EXIT", _
"EXPLAIN", "FALSE", "FETCH", "FLOAT", "FLOAT4", "FLOAT8", "FOR", "FORCE", "FOREIGN", "FROM", "FULLTEXT", "GET", "GRANT", _
"GROUP", "HAVING", "HIGH_PRIORITY", "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IF", "IGNORE", "IN", "INDEX", "INFILE", _
"INNER", "INOUT", "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER", "INTERVAL", "INTO", _
"IO_AFTER_GTIDS", "IO_BEFORE_GTIDS", "IS", "ITERATE", "JOIN", "KEY", "KEYS", "KILL", "LEADING", "LEAVE", "LEFT", "LIKE", _
"LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", "LOCALTIMESTAMP", "LOCK", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", _
"MASTER_BIND", "MASTER_SSL_VERIFY_SERVER_CERT", "MATCH", "MAXVALUE", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", _
"MINUTE_MICROSECOND", "MINUTE_SECOND", "MOD", "MODIFIES", "NATURAL", "NONBLOCKING", "NOT", "NO_WRITE_TO_BINLOG", "NULL", _
"NUMERIC", "ON", "OPTIMIZE", "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", "OUTFILE", "PARTITION", "PRECISION", _
"PRIMARY", "PROCEDURE", "PURGE", "RANGE", "READ", "READS", "READ_WRITE", "REAL", "REFERENCES", "REGEXP", "RELEASE", "RENAME", "REPEAT", _
"REPLACE", "REQUIRE", "RESIGNAL", "RESTRICT", "RETURN", "REVOKE", "RIGHT", "RLIKE", "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", _
"SELECT", "SENSITIVE", "SEPARATOR", "SET", "SHOW", "SIGNAL", "SMALLINT", "SPATIAL", "SPECIFIC", "SQL", "SQLEXCEPTION", "SQLSTATE", _
"SQLWARNING", "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS", "SQL_SMALL_RESULT", "SSL", "STARTING", "STRAIGHT_JOIN", "TABLE", "TERMINATED", _
"THEN", "TINYBLOB", "TINYINT", "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", "UNIQUE", "UNLOCK", "UNSIGNED", "UPDATE", _
"USAGE", "USE", "USING", "UTC_DATE", "UTC_TIME", "UTC_TIMESTAMP", "Values", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", "WHEN", _
"WHERE", "WHILE", "WITH", "WRITE", "XOR", "YEAR_MONTH", "ZEROFILL")
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

economist

#11
Ну а по сабжу - Statement.EscapeProcessing = False  - не помог. Похоже, это сама SQLite так себя ведет.
Так что отлавливайте ошибку программно. То есть если ФИО отсутствующих равно нескольким Absent - то они его приняли дома, и незримо присутствуют на работе/учебе. Не вижу здесь большой беды.

SQLite вообще довольно либеральна к неточностям, Абсента ей не жалко. У Пабло Пикассо есть соответствующая КДПВ: "Любительница Абсента".
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost

Цитата: economist от  9 февраля 2017, 10:04Ну а по сабжу - Statement.EscapeProcessing = False  - не помог
Мне помог. =) ODBC драйвер использовал этот: http://www.ch-werner.de/sqliteodbc/
Спасибо за обстоятельные ответы с примерами и дельные советы. Буду разбираться.

economist

ost - скажете еще вашу версию OpenOffice|LibreOffice и Windows, вдруг кто еще столкнется с проблемой?!
Руб. за сто, что Питоньяк
Любит водку и коньяк!
Потому что мне, без оных, -
Не понять его никак...

ost