Показать сообщение отдельно
Старый 17.02.2011, 12:48   #1
ont
 
Аватар для ont
 
Регистрация: 16.12.2010
Сообщений: 57
Репутация: 92
По умолчанию Альтернативный LIMIT

Затравка.
Приведу альтернативу LIMIT, когда в url нельзя использовать символы: [пробел],`,',/,%
Из-за ограничений отпадают альтернативные пробелы (%09,%0A,...) и /**/. Остается альтернативный синтаксис с использованием скобок. Но синтаксис limit не позволяет даже их:
Код:
... limit(1,100)      --> error
... limit(1),(100)    --> error
... limit(1)          --> error
... limit(1)offset(0) --> error
Совсем без LIMIT
Если в таблице есть уникальные данные для каждой из строк (например колонка id, e-mail, username), и известно точное значение, то в таком случае будет удобнее указать условие в WHERE, которое ограничит выборку до одной строки. К сожалению для information_schema.tables это не так.

Идея и реализация
Суть идеи -- добавить к данным колонку с возрастающими числами (самодельный AUTOINCREMENT) и затем добавить WHERE условие с точным значением для этой колонки.

1) Google услужливо подсказывает:
SELECT @row:=@row+1 r, t.table_name FROM (SELECT @row:=0) r,information_schema.tables t
Код:
+------+---------------------------------------+
| r    | table_name                            |
+------+---------------------------------------+
|    1 | CHARACTER_SETS                        |
|    2 | COLLATIONS                            |
|    3 | COLLATION_CHARACTER_SET_APPLICABILITY |
|    4 | COLUMNS                               |
|    5 | COLUMN_PRIVILEGES                     |
....
2) Переделываем в альтернативный синтаксис (с использованием обратной кавычки ` было бы проще, но ее часто фильтруют):
SELECT(@row:=@row+1)r,(t.table_name)FROM(SELECT@row:=0)r,(select(table_name)from(information_schema.tables))t
Как оказалось, пробел между SELECT и @ можно опустить.

3) Теперь в конце запроса висит символ t, который мешает дописать условие WHERE... Решаем проблему прицепкой известной таблицы, данные из которой мы не будем выбирать. Как оказалось, алиас для такой таблицы не обязателен, что позволяет дописывать условия, но размножает строки (об этом дальше).
Чем меньше строк в дополнительной таблице, тем лучше, в примере выбрана information_schema.engines, т.к. в моем случае это всего 6 строк.
SELECT(@row:=@row+1)r,(t.table_name)FROM(SELECT@ro w:=0)r,(select(table_name)from(information_schema. tables))t,(information_schema.engines)
Код:
+------+----------------+
| r    | table_name     |
+------+----------------+
|    1 | CHARACTER_SETS |
|    2 | CHARACTER_SETS |
|    3 | CHARACTER_SETS |
|    4 | CHARACTER_SETS |
|    5 | CHARACTER_SETS |
|    6 | CHARACTER_SETS |
|    7 | COLLATIONS     |
|    8 | COLLATIONS     |
|    9 | COLLATIONS     |
|   10 | COLLATIONS     |
....
4) Теперь, если дописать where(@row=1) то получим пустое множество, если where(r=1), то ошибку. Правильным решением будет запись having(r=1):
SELECT(@row:=@row+1)r,(t.table_name)FROM(SELECT@ro w:=0)r,(select(table_name)from(information_schema. tables))t,(information_schema.engines)having(r=1)
Код:
+------+----------------+
| r    | table_name     |
+------+----------------+
|    2 | CHARACTER_SETS |
+------+----------------+
1 row in set (0.00 sec)
В результатах выборки значение r будет всегда на единицу больше.

5) Делаем обертку вокруг нашего SELECT, чтобы получить нужную колонку:
SELECT(table_name)FROM(SELECT(@row:=@row+1)r,(t.table_name)FROM(SELECT@ro w:=0)r,(select(table_name)from(information_schema. tables))t,(information_schema.engines)having(r=1))x
Код:
+----------------+
| table_name     |
+----------------+
| CHARACTER_SETS |
+----------------+
1 row in set (0.00 sec)
Использование.
Результат построенного SELECT будет зависеть от значения r в having(r=1). Очевидно, что, если в таблице information_schema.engines было шесть строк, то having(r=N) для N=1..6 даст одинаковые значения. Следующее значение будет получено при N=7...12. Поэтому для получения данных, сначала необходимо экспериментальным путем установить количество строк в information_schema.engines (в моем случае новое значение было получено при N=7 поэтому количество строк равно шести). После чего можно получать данные, подставляя значения N=i*rows_count, где i -- номер значения, rows_count -- количество строк в engines.

P.S. Прошу прощения, если привел уже известное решение или есть решение проще (поэтому запостил сюда)...
P.P.S. Мне кажется или парсер форума местами вставляет пробелы?! В SQL запросах их быть не должно...
ont вне форума   Ответить с цитированием