Как найти ошибку в sql коде

Как найти ошибку в SQL-запросе

SQL-запрос — это то, что либо работает хорошо, либо не работает вообще, частично он никак работать не может, в отличие, например, от того же PHP. Как следствие, найти ошибку в SQL-запросе, просто рассматривая его — трудно, особенно если этот запрос снабжён целой кучей JOIN и UNION. Однако, в этой статье я расскажу о методе поиска ошибок в SQL-запросе.

Поскольку обычно в SQL-запрос подставляются какие-то переменные в PHP, то необходимо его сначала вывести. Сделать это можно, например, так:

<?php
  $a = 5;
  $query = "SELECT FROM `table` WHERE `id` = '$a'";
  $result_set = $mysqli->query($query); // Не работает
  echo $query; // Выводим запрос, который отправляется
?>

В результате, скрипт выведет такой запрос: SELECT FROM `table` WHERE `id` = ‘5’. Теперь чтобы найти ошибку в нём, надо зайти в phpMyAdmin, открыть базу данных, с которой происходит работа, открыть вкладку «SQL» и попытаться выполнить запрос.

И вот здесь уже ошибка будет показана, не в самой понятной форме (иногда прямо точно описывает ошибку), но она будет. Вот что написал phpMyAdmin: «#1064 — You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘FROM `table` WHERE `id` = ‘5’ ORDER BY `table`.`id` ASC LIMIT 0, 30′ at line 1«. Это означает, что ошибка рядом с FROM. Присматриваемся к этому выделенному нами небольшому участку и обнаруживаем, что мы забыли поставить «*«. Исправляем сразу в phpMyAdmin эту ошибку, убеждаемся, что запрос сработал и после этого идём исправлять ошибку уже в коде.

С помощью этого метода я нахожу абсолютно все ошибки в SQL-запросе, которые мне не удаётся обнаружить непосредственно при осмотре в PHP-коде.

Надеюсь, теперь и Вы сможете найти ошибку в любом SQL-запросе.

  • Создано 01.05.2013 10:54:01


  • Михаил Русаков

Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления

Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.

Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

  1. Кнопка:

    Она выглядит вот так: Как создать свой сайт

  2. Текстовая ссылка:

    Она выглядит вот так: Как создать свой сайт

  3. BB-код ссылки для форумов (например, можете поставить её в подписи):

����� 1. ��������� �������.

����� 1. ������.

�������� ������ �� ��� �����, ���� �� �� ��������� ����� ����������, ��� ����� ������� ������ ����� ���� ������� � ������ �������. ��� �� ��ɣ� ����� ��������� � � ��������� SQL ����������.

��� ������ ��������� ������ � ������� ��������. ������ � ���� ������ ��������� ����� ������.


select * fro t1 where f1 in (1,2,1);

� �����, ����������� ��������� ��� �������� � ޣ� ��������. ���� ��������� ���� ������ � mysql cli ������ ������ �ݣ ��������:


mysql> select * fro t1 where f1 in (1,2,1);
ERROR 1064 (42000): You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version
for the right syntax to use near 'fro t1 where f1 in (1,2,1)' at line 1

�� ���� ��� �������������� ������: ������� �������� ����� o � ��������� from. ������, �� ������ ��?

����ͣ� ������ ���������. ��� ��� �� PHP. (��� ��������� ��������� �������, ��� ��� ��� ����������� ��� PHP ����������� � ������. ����������� �������� ����� �������� � �� ����� ������ ����� ������� ����� ����������������.)


$query = 'SELECT * FROM t4 WHERE f1 IN(';
for ($i = 1; $i < 101; $i ++)
$query .= "'row$i,";
$query = rtrim($query, ',');
$query .= ')';
$result = mysql_query($query);

� ������ ������ ��������� ������ ��� �������. � ��� ����� � ������ �ݣ ����� �������� �������?

� ������ � PHP ��� ������� ������� ������� echo, ������� ������������ �����:


$query = 'SELECT * FROM t4 WHERE f1 IN(';
for ($i = 1; $i < 101; $i ++)
$query .= "'row$i,";
$query = rtrim($query, ',');
$query .= ')';
echo $query;
//$result = mysql_query($query);

�������� ������:


$php phpconf2009_1.php
SELECT * FROM t4 WHERE f1 IN('row1,'row2,'row3,'row4,'row5,'row6,'row7,'row8,'row9,'row10,'row11,
'row12,'row13,'row14,'row15,'row16,'row17,'row18,'row19,'row20)

� ��� ��� ������ ���������� ����� ���������: �������� ����������� �������� � ���������


$query .= "'row$i,";

���������� �������� ��� ����������


$query .= "'row$i',";

� ������ ����� ����������� �����.

�������� ��������, ��� �� �������� ������ ������ � ��� ����, � ������� ��� �������� ����. ������� ����� ����� ������ � ������� �������, ��� � ������, ������� ���������� �� ������ ������ ��� �������� ����������.

������������� ��������� ������ ��� ��������� ����������� ������� ����������, �� ����������� ��ɣ�.

��ɣ� 1: ����������� �������� ������ ��� ������ ������� � ��� ����, � ������� ��� �������� ����.

� ��������� �� �� ������ ����� ������������ echo. �������� � ������ ��������� ������������� �������� ����������.

��������� �� ��������� ������.

�������� �������� �� web-�������� �� �������� �����������:


��������� �������

    * �������
    * ����
    * test2
    * test2
    * test2
    * test2
    * test2

������� �������� ����� �������:

<>

��������:

<>

<Go!>

�������� � ���, ��� � ��� �����-�� ������� ������������ ��������� ������ � ���������� ������.

��������� �� ���, ������� �� ��� ��������:


$system = System::factory()
->setName($this->form->get(Field::NAME))
->setDescription(
$this->form->get(Field::DESCRIPTION)
);
DAO::system()->take($system);

���-������ �������? � ����� ������� ������� ����� ������������ � ޣ� ��������, �� � ����� ������ ��� ������ ��������, ������� ���������� ����������� ��� ������������. �ݣ ����� ������� ��� � ���� ������� �������� ����� � ����� ���� ������: � ��� ��� �� ��������� � ����, �� �������.

� PHP ���������� ����� �������� ��� ����������, ������� �������� �� ���������� �������, ����� �� ������� ��� (������) � ���� ��� �� stderr ����� ���, ��� ��������� ����, �� � ������ � �������������� �������, ��������, � Java, ���������� ���ģ��� �����������������. �� � �� ������ ��� ���������� ������.

��� �� ������? � ������ � MySQL �� ����� ��������� general query log:


mysql> set global log_output='table';
Query OK, 0 rows affected (0.00 sec)


mysql> select * from mysql.general_log;
Empty set (0.09 sec)


mysql> set global general_log='on';
Query OK, 0 rows affected (0.00 sec)

��������� ����������.


mysql> select * from mysql.general_log order by event_time desc limit 25G
*************************** 1. row ***************************
  event_time: 2009-10-19 13:00:00
   user_host: root[root] @ localhost []
   thread_id: 10323
   server_id: 60
command_type: Query
    argument: select * from mysql.general_log order by event_time desc limit 25
...
*************************** 22. row ***************************
  event_time: 2009-10-19 12:58:20
   user_host: root[root] @ localhost [127.0.0.1]
   thread_id: 10332
   server_id: 60
command_type: Query
    argument: INSERT INTO `system` (`id`, `name`, `description`) VALUES ('', 'test2', '')
...
mysql> set global general_log='off';
Query OK, 0 rows affected (0.08 sec)

� 22 ������ �� ����� ��� ������. �� �� �������� ����������: ������� INSERT.

��������� ��� �� ����� � ������� system:


mysql> select * from system;
+----+---------+------------------------------------------+
| id | name    | description                              |
+----+---------+------------------------------------------+
|  1 | �������  | ��������������� ������� � ������� ������      |
|  2 | ����     | �������� �������������� �����                 |
|  3 | test2   | New test                                 |
|  4 | test2   | foobar                                   |
|  8 | test2   |                                          |
+----+---------+------------------------------------------+
5 rows in set (0.00 sec)

��������� ţ �����������:


mysql> show create table systemG
*************************** 1. row ***************************
       Table: system
Create Table: CREATE TABLE `system` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `description` tinytext NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8
1 row in set (0.09 sec)

���� name �� �������� ����������. ������� �� ����� ������ �������� � ����������� ����� ���������: ����� ���� ������� ��� ���� ����������


(alter table system add unique(name))

���� �������� ���������� ����� �������, ����� ��� �������� �������������� �� �� ������ SQL.

�� ������ ��� ����������� ��������� ��ɣ�: ����������� general query log ��� ��������� �������, ������� �������� ������������ ���������.

��ɣ� 2: ����������� general query log, ���� ��� ����� ���������� ����� ������ ������ �������� ������������ ��������� ������ ����������.

�� ���������, ��� ����������� ������ ����� �������� ������, ��������� �������� � ����������. � ����������� ������� ����� ����������, ����� ����� � ��������� ������. ��� ���������, ������ ������� ����� ������� ������ � ������ ������ ��� ������ ����������� �������. �������, ���������� ��������, ����� ����������� ���������� ������� �� ����������. ��� �������� ����� ����������� ��������.
� ������ �� �������� ���� �������� �� ��������� �������:


mysql> select * from mysql.general_log;
Empty set (0.09 sec)


mysql> set global general_log='on';
Query OK, 0 rows affected (0.00 sec)

...

mysql> set global general_log='off';
Query OK, 0 rows affected (0.08 sec)

����� ��� ����� �������� �������� ���������� ����������, ���� �� ����� �������� general query log � ���������������� �����?

���� � ���, ��� general query log ��� �� ���� ������ �����������: �� ����������� �������� �� ������ � ��� ��� �� �������� ��� �������, �� ��� ����� ���ģ��� ������� �� ������ �� �����. ������� �� � ������ 5.1 ��� ����� ��������-��������� � ������ ��������� ������� ��� ����� ����� �������������� �������� �� MySQL ������ � ��������.

��������� ������ �������� ����� �� � ����, � � �������. ����� � ������� ����� ��� ��������� ����� ���������� �������� ��� � ��������� 2-�� ��������, ��� ��� ������� ����� �������������: �� ����������� � ��� ����� ��� � ����� ������ �������.


mysql> set global log_output='table';
Query OK, 0 rows affected (0.00 sec)

Время на прочтение
1 мин

Количество просмотров 1.1K

По мотивам своего мастер-класса на PHPConf 2009 (http://phpconf.ru) я написала гид для тех, кому нужно поймать ошибку в SQL приложении. Правильнее было бы назвать в MySQL приложении, но я всё-таки думаю, что общие принципы едины для всех. В идеале мне бы хотелось, чтобы текст охватывал основные случаи неправильного поведения. Оговорюсь, что под неправильным поведением я понимаю логические ошибки, а не проблемы производительности. Проблемы производительности — это отдельная тема, кстати, достаточно хорошо представленная в сети.

Книжка состоит из 4 частей, ниже можно посмотреть краткое содержание:

Часть 1. Одиночные запросы.
Рассмотрены случаи, когда ошибка повторяется для одного клиента-потока.

Часть 2. Конкурентные запросы.
Случаи, когда ошибка повторяется только в случаях, когда несколько клиентов работают с базой одновременно.

Часть 3. Другие случаи.
Случаи, не подходящие под предыдущие определения.

Часть 4. Техники, применяющиеся для отладки Production приложений.
Краткий перечень того, что нужно делать, если приходится тестировать на рабочем сервере.

Текст получился достаточно объёмный, поэтому я посчитала нужным дать ссылку на внешний ресурс, а не выкладывать здесь, так как получилось достаточно «много букаф», а несколько постов подряд на одну тему может утомить.

Пожалуйста, почитайте и покритикуйте. Ваше мнение очень интересно. Комментарии оставляйте здесь :)

Почитать можно здесь: sql-error.microbecal.com

SQL queries are easy to learn and reuse.

The difficulty of reading and understanding current SQL queries is known as query interpretation. It’s frequently as difficult as Query Composition, which entails writing a new query.

SQL Syntax Checker validates and marks any errors in your SQL queries.

Common Causes of Syntax Errors

  • Mismatched number of open and close parentheses
  • Improper query language used 
  • The data required for the query is missing
  • Typos
  • Syntax errors such as misspelling
  • Use of Reserved words
  • An old version of the keyword is used
  • Misspelling a keyword or function name

How to Validate Syntax and Disable Statement Execution

Before executing SQL on your production database server, you can run a SQL syntax check without connecting to the database server and look for syntax issues.
The following are supported by the database: Oracle (PLSQL), SQL Server, MySQL, DB2, and Access are all examples of database management systems.
When you’re debugging and come across any syntax that’s part of a long query and wants to validate it, all you have to do is use Syntax.

SQL is the Language used to Communicate with Databases

SQL, SQL Server, MySQL, PostgreSQL, Oracle, and so on. You want to learn SQL, but you’re intimidated by the number of keywords and don’t know where to begin. Let’s go over the definitions for each of these terms.

A database is a type of computer program that stores and processes vast volumes of information. Database vendors come in a variety of shapes and sizes. Database products from different vendors include PostgreSQL, MySQL, Oracle, and SQL Server. The programming language SQL is used to communicate with these databases, and each database product has its SQL variant. These variations are referred to as SQL dialects.

Using SQL Queries to Create Visualizations

Many individuals have tried but failed to create a successful parser due to the intricacy of the SQL grammar and dialicts. Our parser reduces the problems of deciphering SQL grammar. The parsing logic generates an abstract syntax tree (AST) containing «raw» or optionally qualified table and column IDs.

AST Tree Algorithm

The parsing stage entails breaking down the components of a SQL statement into a data structure that may be processed by subsequent algorithms. The database only parses a statement when the application tells it to. Therefore only the application, not the database, may reduce the number of parses. Various utility function analyze the AST tree to identify the components:

  1. what tables appear in the query?
  2. what columns appear in the query, per clause?
  3. what is the table/column lineage of a query?
  4. what sets of columns does a query compare for equality?

Designing Queries

Соблюдение нескольких соглашений значительно облегчает поиск ошибок в запросах,особенно когда вы обращаетесь за помощью к людям,которые могут знать SQL,но ничего не знают о вашей конкретной схеме.Легко читаемый запрос-это легко отлаживаемый запрос.Используйте пробельные символы для группировки предложений в запросе.Выбирайте хорошие псевдонимы таблиц и полей,чтобы добавить ясности,а не путаницы.Выбирайте синтаксис,который поддерживает смысл запроса.

Using Whitespace

Трудночитаемый запрос-трудноотлаживаемый запрос.Белое пространство свободно.Новые строки и отступы облегчают чтение запросов,особенно при построении запроса на языке сценариев,где переменные перемежаются по всему запросу.

В приведенном ниже тексте допущена синтаксическая ошибка.Как быстро вы сможете ее найти?

SELECT u.id, u.name, alliance.ally FROM users u JOIN alliance ON
(u.id=alliance.userId) JOIN team ON (alliance.teamId=team.teamId
WHERE team.teamName='Legionnaires' AND u.online=1 AND ((u.subscription='paid'
AND u.paymentStatus='current') OR u.subscription='free') ORDER BY u.name;

Вот тот же запрос с правильным использованием пробельных символов.Можете ли вы быстрее найти ошибку?

SELECT
    u.id
    , u.name
    , alliance.ally
FROM
    users u
    JOIN alliance ON (u.id = alliance.userId)
    JOIN team ON (alliance.teamId = team.teamId
WHERE
    team.teamName = 
    AND u.online = 1
    AND (
        (u.subscription = 
        OR
        u.subscription = 
    )
ORDER BY
    u.name;

Даже если вы не знаете SQL,вы все равно могли заметить отсутствие ‘)’ после team.teamId.

Точный стиль форматирования,который вы используете,не так важен.Возможно,вы хотите,чтобы запятые в списке выбора следовали за выражениями,а не предшествовали им.Вы можете делать отступы с помощью табуляции или пробелов.Соблюдение определенной формы не имеет значения.Единственной целью является наглядность.

Псевдонимы таблиц и полей

Псевдонимы позволяют переименовывать таблицы и поля для использования в запросе.Это может быть удобно,когда исходные имена очень длинные,и требуется для самосоединений и некоторых подзапросов.Однако неправильно подобранные псевдонимы могут не облегчить,а усложнить отладку запроса.Псевдонимы должны отражать оригинальное имя таблицы,а не произвольную строку.

Bad:

SELECT *
FROM
    financial_reportQ_1 AS a
    JOIN sales_renderings AS b ON (a.salesGroup = b.groupId)
    JOIN sales_agents AS c ON (b.groupId = c.group)
WHERE
    b.totalSales > 10000
    AND c.id != a.clientId

По мере роста списка объединенных таблиц и предложения WHERE возникает необходимость неоднократно возвращаться к началу запроса,чтобы узнать,к какой таблице относится тот или иной псевдоним.

Better:

SELECT *
FROM
    financial_report_Q_1 AS frq1
    JOIN sales_renderings AS sr ON (frq1.salesGroup = sr.groupId)
    JOIN sales_agents AS sa ON (sr.groupId = sa.group)
WHERE
    sr.totalSales > 10000
    AND sa.id != frq1.clientId

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

Размещение условий JOIN

Руководство предостерегает от использования условия JOIN (то есть,предложения ON)для ограничения строк.Некоторые запросы,особенно те,которые используют неявные соединения,принимают противоположную крайность-все условия соединения переносятся в предложение WHERE.В результате отношения в таблице смешиваются с бизнес-логикой.

Bad:

SELECT *
FROM
    family,
    relationships
WHERE
    family.personId = relationships.personId
    AND relationships.relation = 'father'

Не копаясь в пункте WHERE,невозможно сказать,что связывает эти две таблицы.

Better:

SELECT *
FROM
    family
    JOIN relationships ON (family.personId = relationships.personId)
WHERE
    relationships.relation = 

Связь между таблицами очевидна сразу.Предложение WHERE оставлено для ограничения строк в наборе результатов.

Соблюдение такого ограничения сводит на нет использование оператора запятой для объединения таблиц.Это небольшая цена.Запросы в любом случае следует писать с использованием явного ключевого слова JOIN,и эти два оператора никогда не следует смешивать (если только вам не нравится переписывать все свои запросы каждый раз,когда в новой версии меняется приоритет оператора).

Поиск синтаксических ошибок

Синтаксические ошибки-одни из самых легко решаемых проблем.MariaDB выдает сообщение об ошибке,показывающее точное место,где синтаксический анализатор запутался.Проверьте запрос,включая несколько слов перед фразой,показанной в сообщении об ошибке.Большинство синтаксических и синтаксических ошибок очевидны после второго взгляда,но некоторые из них более неуловимы,особенно когда текст ошибки кажется пустым,указывает на правильное ключевое слово,или кажется,что ошибка в синтаксисе,который кажется совершенно правильным.

Интерпретация пустой ошибки

Большинство синтаксических ошибок легко интерпретировать.В ошибке обычно указывается точный источник проблемы.Внимательное изучение запроса с учетом сообщения об ошибке часто позволяет обнаружить очевидную ошибку,например,неправильно написанные имена полей,пропущенное ‘AND’ или лишнюю закрывающую скобку.Иногда ошибка оказывается не столь полезной.Частое,менее полезное сообщение:

ERROR 1064: You have an error in your SQL syntax; check the manual that corresponds to your
MariaDB server version for the right syntax to use near 

Пустое ‘ ‘ может обескуражить.Очевидно,что произошла ошибка,но где? Хорошее место для поиска-конец запроса.’ ‘ говорит о том,что синтаксический анализатор достиг конца высказывания,но все еще ожидает появления синтаксического маркера.

Проверьте,нет ли отсутствующих закрывающих элементов,таких как ‘ и ):

SELECT * FROM someTable WHERE field = 

Ищите неполные предложения,которые часто обозначаются открытой запятой:

SELECT * FROM someTable WHERE field = 1 GROUP BY id,

Проверка наличия ключевых слов

MariaDB допускает имена таблиц и полей, а также псевдонимы, которые также являются зарезервированными словами . Во избежание двусмысленности такие имена должны быть заключены в обратные кавычки (`):

SELECT * FROM actionTable WHERE `DELETE` = 1;

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

Текстовый редактор с цветовой подсветкой синтаксиса SQL помогает найти эти ошибки.Когда вы вводите имя поля,а оно отображается тем же цветом,что и ключевое слово SELECT,вы знаете,что что-то не так.Некоторые распространенные ошибки:

  • DESC — это обычное сокращение для полей «описание». Это означает «нисходящий» в предложении MariaDB ORDER .
  • DATE , TIME и TIMESTAMP являются общими именами полей. Они также являются типами полей.
  • ЗАКАЗ появляется в приложениях для продаж. MariaDB использует его для указания сортировки результатов.

Некоторые ключевые слова настолько распространены,что MariaDB делает специальное разрешение на их использование без кавычек.Мой совет:не делайте этого.Если это ключевое слово,заключите его в кавычки.

Синтаксис,зависящий от версии

По мере добавления в MariaDB новых функций синтаксис должен меняться для их поддержки.В большинстве случаев старый синтаксис будет работать в новых версиях MariaDB.Заметным исключением является изменение приоритета оператора запятой по отношению к ключевому слову JOIN в версии 5.0.Запрос,который раньше работал,например

SELECT * FROM a, b JOIN c ON a.x = c.x;

теперь не получится.

Однако более распространенной является попытка использовать новый синтаксис в старой версии.Известно,что хостинговые компании медленно обновляют MariaDB,и вы можете обнаружить,что используете версию,устаревшую на несколько лет.Результат может быть очень неприятным,когда запрос,который безупречно выполняется на вашей собственной рабочей станции с последней версией,не работает в производственной среде.

Этот запрос не работает в любой версии MySQL до 4.1,когда на сервер были добавлены подзапросы:

SELECT * FROM someTable WHERE someId IN (SELECT id FROM someLookupTable);

Этот запрос не работает в некоторых ранних версиях MySQL,поскольку синтаксис JOIN изначально не допускал предложения ON:

SELECT * FROM tableA JOIN tableB ON tableA.x = tableB.y;

Всегда проверяйте установленную версию MariaDB и читайте раздел руководства,относящийся к этой версии.В руководстве обычно указывается,когда именно конкретный синтаксис стал доступен для использования.

Содержание,воспроизводимое на этом сайте,является собственностью соответствующих владельцев,и это содержание не просматривается заранее компанией MariaDB.Взгляды,информация и мнения,выраженные в этом содержании,не обязательно представляют собой взгляды,информацию и мнения,выраженные MariaDB или любой другой стороной.

Понравилась статья? Поделить с друзьями:
  • Как найти ошибку в sql запросе
  • Как найти ошибку в безопасном режиме
  • Как найти ошибку в robot txt
  • Как найти ошибку в php сайте
  • Как найти ошибку в pascal