Проверьте схему SQL на наличие зарезервированных слов и найдите подходящую замену

Потратил много часов на устранение неполадок в моей БД, которая включала maxValue в качестве имени столбца. С тех пор я обнаружил, что это зарезервированное слово.

Я использовал type и timestamp как с MySQL, так и с MariaDB без проблем, но я усвоил урок и никогда не буду делать этого снова (MySQL показывает, что оба зарезервированы, но MariaDB показывает только timestamp и даже говорит, что его все еще можно использовать ).

  1. Есть ли какой-нибудь онлайн-инструмент, который проверит схему с помощью дампа SQL или создаст SQL для зарезервированных слов?
  2. Есть ли какой-либо ресурс или стратегия, показывающая типичные слова-заменители. Я полагаю, что могу сделать их множественными, но это противоречит моим кадровым стандартам.

person user1032531    schedule 05.09.2017    source источник
comment
Зарезервированные слова хорошо задокументированы: dev.mysql.com/doc/refman/ 5.7/ru/keywords.html. Множественное число помогает (и я использую его для имен таблиц), но некоторые зарезервированные слова, такие как VALUES и READS, имеют форму множественного числа.   -  person Gordon Linoff    schedule 05.09.2017
comment
Да, они Гордон, но я не нашел ни инструмента для проверки, ни рекомендаций по замене слов. Запрашивает ли инструмент здесь не по теме? А как насчет замены?   -  person user1032531    schedule 05.09.2017
comment
Я думаю, что некоторые инструменты с графическим интерфейсом определяют плохой синтаксис. Однако рекомендация инструмента выходит за рамки Stack Overflow.   -  person Gordon Linoff    schedule 05.09.2017
comment
это может вам помочь: stackoverflow.com/questions /8339396/   -  person Esteban P.    schedule 05.09.2017
comment
Насколько я могу судить, не верстак mysql. Даже не искать рекомендации, а просто узнать, доступны ли они. Может быть, я должен написать один, когда у меня будет время, так как я думаю, что это будет полезно для других.   -  person user1032531    schedule 05.09.2017
comment
@ЭстебанП. Я видел пару таких, но они требуют, чтобы пользователь вводил по одному слову за раз. Я пытался даже вывести несколько строк SQL для каждого из перечисленных инструментов, но ни один из них не сработал.   -  person user1032531    schedule 05.09.2017
comment
Это нехорошее решение, но если вы заключите зарезервированные слова в обратные кавычки, они будут пониматься как имена столбцов, т.е. `timestamp`   -  person RiggsFolly    schedule 05.09.2017
comment
@RiggsFolly Я чувствую, что обратные галочки будут помощником, который доставит мне неприятности в будущем.   -  person user1032531    schedule 05.09.2017
comment
вы можете получить все зарезервированные слова с помощью: SELECT * FROM mysql.help_keyword - следующим шагом будет поиск этих слов в вашем коде   -  person Esteban P.    schedule 05.09.2017
comment
На самом деле создать такой инструмент будет достаточно просто. Может быть, стоит сделать его общедоступным? Что-то вроде select * from information_schema.columns where table_schema = 'your_db' order by table_name,ordinal_position вместе с последним запросом комментария Эстебана подойдет.   -  person user1032531    schedule 05.09.2017
comment
Было бы проще написать инструмент для запуска перед проектированием базы данных, которая просто повторяет строку Read the manual first   -  person RiggsFolly    schedule 05.09.2017
comment
@RiggsFolly Какое руководство? Maria DB имеет 233 зарезервированных слова плюс 8 исключений (которые, я думаю, являются зарезервированными словами, которые вы можете использовать). MySQL имеет 622 зарезервированных слова. Действительно, вероятно, не следует использовать какие-либо зарезервированные слова для какой-либо общей БД для улучшения переносимости. Извините, я еще не запомнил их и не знал, что maxValue был одним из них. У вас есть?   -  person user1032531    schedule 05.09.2017
comment
НЕТ! Но довольно очевидно, что можно догадаться, т.е. звучит ли это как команда SQL или тип данных? И я использую руководство, если я в чем-то не уверен. Есть старая пословица measure twice, cut once   -  person RiggsFolly    schedule 05.09.2017
comment
SQL был изобретен несколько десятилетий назад, когда были приняты зарезервированные слова. Perl и PHP предпочли префикс $ для всех переменных, тем самым избегая этого. PL/I настаивал на том, чтобы ни одно слово не было зарезервировано, что создавало кошмар для разработчиков и читателей. Это верно: IF IF THEN THEN ELSE ELSE END; Слова 2,4,6 являются переменными; остальное синтаксис.   -  person Rick James    schedule 05.09.2017


Ответы (1)


Для чего это стоит, вот инструмент ...

Обратите внимание, что mysql.help_keyword не поддерживается в MariaDB 10.2.7, и мне пришлось жестко кодировать зарезервированные слова.

<?php
error_reporting(E_ALL);
ini_set('display_startup_errors', 1);
ini_set('display_errors', 1);
openlog('API', LOG_NDELAY, LOG_LOCAL2);

if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST['database'])) {

    $db=parse_ini_file(__DIR__.'/../config.ini',true)['mysql'];
    $pdo=new PDO("mysql:host={$db['host']};dbname={$db['dbname']};charset={$db['charset']}",$db['username'],$db['password'],array(PDO::ATTR_EMULATE_PREPARES=>false,PDO::MYSQL_ATTR_USE_BUFFERED_QUERY=>true,PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_OBJ));

    $error=['tableHelper'=>[],'columnHelper'=>[],'tableMdbReserved'=>[],'columnMdbReserved'=>[],'tableMdbException'=>[],'columnMdbException'=>[]];
    $stmt=$pdo->query('SELECT name FROM mysql.help_keyword');
    $reserved=$stmt->fetchAll(PDO::FETCH_COLUMN);
    $mdbReserved=['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','GENERAL','GRANT','GROUP','HAVING','HIGH_PRIORITY','HOUR_MICROSECOND','HOUR_MINUTE','HOUR_SECOND','IF','IGNORE','IGNORE_SERVER_IDS','IN','INDEX','INFILE','INNER','INOUT','INSENSITIVE','INSERT','INT','INT1','INT2','INT3','INT4','INT8','INTEGER','INTERVAL','INTO','IS','ITERATE','JOIN','KEY','KEYS','KILL','LEADING','LEAVE','LEFT','LIKE','LIMIT','LINEAR','LINES','LOAD','LOCALTIME','LOCALTIMESTAMP','LOCK','LONG','LONGBLOB','LONGTEXT','LOOP','LOW_PRIORITY','MASTER_HEARTBEAT_PERIOD','MASTER_SSL_VERIFY_SERVER_CERT','MATCH','MAXVALUE','MEDIUMBLOB','MEDIUMINT','MEDIUMTEXT','MIDDLEINT','MINUTE_MICROSECOND','MINUTE_SECOND','MOD','MODIFIES','NATURAL','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','RECURSIVE','REFERENCES','REGEXP','RELEASE','RENAME','REPEAT','REPLACE','REQUIRE','RESIGNAL','RESTRICT','RETURN','REVOKE','RIGHT','RLIKE','ROWS','SCHEMA','SCHEMAS','SECOND_MICROSECOND','SELECT','SENSITIVE','SEPARATOR','SET','SHOW','SIGNAL','SLOW','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'];
    $mdbExceptions=['ACTION','BIT','DATE','ENUM','NO','TEXT','TIME','TIMESTAMP'];

    $stmt=$pdo->prepare('SELECT UPPER(TABLE_NAME) tn, UPPER(COLUMN_NAME) cn from information_schema.columns WHERE table_schema = ?');
    $stmt->execute([$_POST['database']]);
    while($rs=$stmt->fetch()) {
        if(in_array($rs->tn,$reserved)) {
            $error['tableHelper'][]=$rs->tn;
        }
        if(in_array($rs->cn,$reserved) && !in_array($rs->cn,$error['columnHelper'])) {
            $error['columnHelper'][]=$rs->cn;
        }
        if(in_array($rs->tn,$mdbReserved)) {
            $error['tableMdbReserved'][]=$rs->tn;
        }
        if(in_array($rs->cn,$mdbReserved) && !in_array($rs->cn,$error['columnMdbReserved'])) {
            $error['columnMdbReserved'][]=$rs->cn;
        }
        if(in_array($rs->tn,$mdbExceptions)) {
            $error['tableMdbException'][]=$rs->tn;
        }
        if(in_array($rs->cn,$mdbExceptions) && !in_array($rs->cn,$error['columnMdbException'])) {
            $error['columnMdbException'][]=$rs->cn;
        }
    }
    echo('<pre>'.print_r($error,1).'</pre>');
}
else {
    echo <<<EOT
<form method="post">
  Database Name: <input type="text" name="database"><br>
  <input type="submit">
</form>
EOT;
}

Выход:

Array
(
    [tableHelper] => Array
        (
        )

    [columnHelper] => Array
        (
            [0] => TYPE
            [1] => NAME
            [2] => TIMESTAMP
            [3] => OFFSET
            [4] => VALUE
            [5] => STATUS
            [6] => PORT
        )

    [tableMdbReserved] => Array
        (
        )

    [columnMdbReserved] => Array
        (
            [0] => MAXVALUE
        )

    [tableMdbException] => Array
        (
        )

    [columnMdbException] => Array
        (
            [0] => TIMESTAMP
        )

)
person user1032531    schedule 05.09.2017
comment
После всего этого maxValue не появляется! Очевидно, за mysql.help_keyword не следят. - person user1032531; 05.09.2017