Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

SQL-запросы и разбор параметров.

369
20 февраля 2011 года
Kesano
451 / / 09.10.2007
Салют, друзья.
Хочу сделать обертку для SQL-запросов.
И возник вопрос, как играться с логикой (AND, OR), и как лучше составлять запросы.
Нужен ваш совет и, по возможности, примеры.

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

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

из формы передаем
 
Код:
$price_from=2000;
$price_to=5000;
$diamond=1;//true
$category=array('Кольца','Подвески','Серьги');

foreach($category as $key=>$val) {
      $category[$key]="category='".$val."'";
      }
 $sql_cat="AND (".implode(' OR ', $category).")";
 $sql="select * from items where (price>='$price_from' AND price<='$price_to' AND diamond='$diamond'".$sql_cat.")";

и запрос получается:
 
Код:
select * from items where (price>='2000' AND price<='5000' AND diamond='1'AND (category='Кольца' OR category='Подвески' OR category='Серьги'))

Вопрос:
как более грамотно и точно:
1.Собрать переменные для собирания "where"
2.Если в одном поле моет быть несколько совпадения, чтобы у нас получилось нужное количество логических операторов, т.е. чтобы не вышло "$cat=a1 or $cat=a2 or"... т.е. чтобы их небыло лишних в начале или конце... Я пока остановился на implode... но мож что другое посоветуете?

Буду благодарен за примеры и за ссылки на краткие, но очень доходчивые примеры и статьи.
274
20 февраля 2011 года
Lone Wolf
1.3K / / 26.11.2006
Не совсем понял в чем суть вопроса. но подскажу как избавится от кучи and-ов

 
Код:
$price_from=2000;
$price_to=5000;
$diamond=1;//true
$category=array('Кольца','Подвески','Серьги');

 $sql="select * from items where (price>='$price_from' AND price<='$price_to' AND diamond='$diamond' AND category in  (".implode(',',$category)."))";


Будет так
 
Код:
select * from items where (price>='2000' AND price<='5000' AND diamond='1'AND category IN ('Кольца','Подвески',Серьги'))
369
20 февраля 2011 года
Kesano
451 / / 09.10.2007
Спасибо, УЖЕ полезно и упрощает код в разы... Т.е. мы как бы продолжаем работать с массивом, только уже в самом запросе благодаря оператору IN..
Вот только твой код выдает:
select * from items where (price>='2000' AND price<='5000' AND diamond='1' AND category in (Кольца,Подвески,Серьги))
т.е. значения категорий без одинарных кавычек...
Или обрабатывать массив foreach'ем, добавляя одинарные кавычки, или... ?
10
20 февраля 2011 года
Freeman
3.2K / / 06.03.2004
Цитата: Kesano
Или обрабатывать массив foreach'ем, добавляя одинарные кавычки, или... ?


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

 
Код:
select * from items where price between 2000 and 5000 and diamond = 1 and category in (1, 2, 3)

Почти без скобок и кавычек.
369
20 февраля 2011 года
Kesano
451 / / 09.10.2007
Цитата: Freeman
При полной нормализации категории должны браться из справочника категорий и быть числовыми кодами.
 
Код:
select * from items where price between 2000 and 5000 and diamond = 1 and category in (1, 2, 3)

Почти без скобок и кавычек.



Ну собственно, да, они и будут числовыми значениями...

 
Код:
price between 2000 and 5000 and diamond = 1

Мускуль нормально воспример два AND без кавычек, не будет капать дальше???
 
Код:
(price between 2000 and 5000) and diamond = 1

?
369
22 февраля 2011 года
Kesano
451 / / 09.10.2007
Собственно, нужна ещё ваша помощь и совет по данному вопросу:
Как лучше разбирать форму поиска по базе?
например, есть критерии price_from,price_to, category, diamond. (сразу говорю, не пишу интернет-магазин, персонажи вымышлены)
но передаются не все из них.
как бы более гибко описать чтение $_POST, чтобы он находя непустые поля, добавлял их к запросу автоматически?
Моя соображалка пока не готова родить функцию для этого.
Например переданы только price_to и diamond.
И чтобы скрипт сжирал их из ПОСТа и добавлял к запросу.

Вопрос у УАСу:
ты писал про то что переопределение переменных - зло.
как-то без "foreach" можно пройтись по ПОСТу и обработать каждое значение тримами и эскейп_стрингами?
Или единсвенный вариант - писать функцию валидности значения для каждого переданного параметра и перезаписи ПОСТа з функции?
5
22 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Я не очень понимаю зачем выполнять тримы и эскейпы.
В MSSQL динамическое построение запроса выглядит следующим образом (и я думаю такой же подход реализуем в MySql):
Формируем строку вида
 
Код:
SELECT a,b,c,d
FROM dbo.MyTable
WHERE 1 != 0
  AND x < @x
  AND y > @y
  AND z = @z
ORDER BY a,b,c,d

AND условия просто цепляются к строке при наличии тех или иных параметров.
Выполнение запроса происходит c передачей параметров, которые есть в запросе (синтаксис T-SQL):
 
Код:
EXEC(@query, @x = @actualX, @y = @actualY, @x = @actualZ)

Такой же подход можно реализовать на клиенте. И что самое главное - никаких фактических значений мы не пихаем в строку - только идентификаторы.


Полный пример:
Код:
DECLARE @query NVARCHAR(MAX)
SET @query = N'
  SELECT a,b,c,d
  FROM dbo.MyTable
  WHERE 1 != 0';

IF(@x IS NOT NULL)
  SET @query = @query + N' AND x < @x';
IF(@y IS NOT NULL)
  SET @query = @query + N' AND y > @y';
IF(@z IS NOT NULL)
  SET @query = @query + N' AND z = @z';

SET @query = @query + N' ORDER BY a,b,c,d';

EXEC(@query, @x = @x, @y = @y, @x = @z);
369
22 февраля 2011 года
Kesano
451 / / 09.10.2007
Цитата: hardcase
Я не очень понимаю зачем выполнять тримы и эскейпы.
В MSSQL динамическое построение запроса выглядит следующим образом (и я думаю такой же подход реализуем в MySql):



Тримы и эскейпы для того, чтобы нам в запрос не передали какую-то лабуду + пробелы с числом + SQL-инъекции и т.д.
В принципе, я рассматривал вопрос "WHERE 1" и потом в цикле перед парой "ключ-значение" ставить AND... Насколько это корректно и грамотно?

5
22 февраля 2011 года
hardcase
4.5K / / 09.08.2005
Цитата: Kesano
Тримы и эскейпы для того, чтобы нам в запрос не передали какую-то лабуду + пробелы с числом + SQL-инъекции и т.д.
В принципе, я рассматривал вопрос "WHERE 1" и потом в цикле перед парой "ключ-значение" ставить AND... Насколько это корректно и грамотно?


Я ведь привел пример. Передавать значение нужно через параметр (имя "переменной") sql-запроса, а в запросе только имя переменной указывать.

369
22 февраля 2011 года
Kesano
451 / / 09.10.2007
Извини, Хард, твой пример с MSSQL для меня как минимум чужд... Как максимум не помогает в решении моей задачи, потому что речь больше идёт о разборе переданных данных посредством PHP.
Пока меня интересует оптимальный алгоритм разбора переданных данных и формирования однострочного SQL-запроса в проекции MySQL...
274
22 февраля 2011 года
Lone Wolf
1.3K / / 26.11.2006
Хм. а если сформировать маисв where-частей, а потом implode(' AND ', $whereParts) ?
Формировать можно и перебеором, и без него. зависит, сколько лишних дынных в post-е
369
22 февраля 2011 года
Kesano
451 / / 09.10.2007
Цитата: Lone Wolf
Хм. а если сформировать маисв where-частей, а потом implode(' AND ', $whereParts) ?
Формировать можно и перебеором, и без него. зависит, сколько лишних дынных в post-е



Нет... В любом случае нужно предусматривать логику AND\OR... при чем я ХЗ как написать умную функцию, которая была бы способна работать с хитрыми конструкциями типа
(col=val AND col2=val2) OR (col=val2 AND col2=val)
Ну и ясное дело, с автоматическим разбором параметров...

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

244
22 февраля 2011 года
UAS
2.0K / / 19.07.2006
Цитата: Kesano
опрос у УАСу:
ты писал про то что переопределение переменных - зло.
как-то без "foreach" можно пройтись по ПОСТу и обработать каждое значение тримами и эскейп_стрингами?
Или единсвенный вариант - писать функцию валидности значения для каждого переданного параметра и перезаписи ПОСТа з функции?


Ну вроде как есть функция array_map, т.е. делаешь $_POST = array_map("trim", $_POST); и получаешь от-trim-енный массив.
Посчет эскейпов - я делаю ескейпы уже на этапе вставки в БД, если это статический запрос (т.е. без множества слйчайных AND, OR ...). А в твоем случае - ну я обычно просто пишу WHERE 1 и далее уже типа:

 
Код:
$sql = "... WHERE 1";
if( $_POST["ololo"] == "1" || $_POST["ololo"] == "10" )
    $sql .= " AND `ololo` = ".$_POST["olollo"];


Посчёт того, использовать isset($_POST[...]) или нет, то я обычно устанавливаю всем переменным значения по-умолчанию. И если $_POST["ololo"] не существует, то создаю такой элемент и присваиваю ему, допустим, пустую строку.

По поводу поста хардкейса - нет, в mysql нет такой возможности, максимум добиться "параметризированного" запроса можно только с помощью sprintf, vsprintf ну или написать свою функцию с параметрезированным вводом (что, обычно, лень =))

Ну а по поводу умной функции для AND OR - тут сложнее, всё-таки, ибо надо углядеть кучу параметров и т.д. Проще сделать на if, или же создавать какую-то структуру из массивов/классов, передавать их в функцию, которая и будет строить условия, т.е. типа:
Код:
// описание условия (одного условия, которое потом будет ветвится на множество)
class Conclusion {
    public String $key;    // поле, например, price
    public Object $value; // значение, например 10, или объект класса AND или OR
}

class AND {
    // массив значений для Conclusion, которые будут объединятся по AND, могут тоже быть AND, OR, Conclusion
    public Object[] $values = array();
}
class OR {
    public Object[] $values = array(); // аналогично AND
}

Вот в этом псевдо-php-java коде видно, как примерно строить условия. Т.е. строится такая иерархия, которая передается в функция, а та уже строит строку. Но, имхо, это такой маразм и тормознутость получится, что легче все на if сваять - проще, быстрее, очевиднее, надежнее.
15
23 февраля 2011 года
shaelf
2.7K / / 04.05.2005
А не проще взять готовую ORM и посмотреть как там все устроено? Мне в этом плане нравится Java разработчики, у них есть хибернейт и они не парятся, это стандарт де факто и его юзают (тока если нужно ппц какая оптимизация, пишут что-то очень легкое свое).
369
23 февраля 2011 года
Kesano
451 / / 09.10.2007
2 shaelf
Мы не ищем лёгких путей :))))

2 UAS
за array_map - спасибо... Можно любую функцию (включая пользовательскую) подвесить на это дело.

со сложным разбором AND\OR я тоже заморачиваться пока не стану... как и с объектами...
У меня БД действительно не сложная, и я ограничусь лишь функциями по предварительному разбору переданных данных и фомированием SQL-запросов для поиска по базе.. остальное, вероятно, будет на ИФах....
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог