Как стать автором
Обновить

Комментарии 13

Не совсем поняла преимущества конструктора where по сравнению с тем же Yii-шным или Laravel -ским (Оба умеют без ActiveRecord запросы формировать)
Разве что фишка маппинга ответа по шаблону интересна

Разница в подходе. У Yii есть 3 уровня абстракции Active Record, Построитель запросов и DAO. Конструктор where у yii находится на уровне построителя запросов, на этом уровне невозможно написать любой sql запрос, оно и понятно в yii сделали так, что при написании запросов с помощью построителя запросов ты не привязан к БД. А мне нужно писать sql запросы использующие уникальные возможности определенной БД (Oracle). Мне нужен уровень DAO, а на нем нет конструктора where. К примеру, у меня может быть запрос на несколько экранов с множеством вложенных запросов в которых будут свои where части, которые я хочу генерировать с помощью конструктора where. В GP это можно сделать. И к слову на момент написания GreenPig в нашей компании проекты были на php 5.3, а для Laravel или Yii2 нужен минимум 5.4 (слава Богу сейчас перешли на 5.4 ))))) )
Вообще интересно, а где происходит склейка данных из ответа базы? В PHP? А так мне и для сложных запросов с кучей join, where, subqueries, json (я юзал postgres) хватало Laravel 5.0 с ActiveRecord, потом правда тоже родился велосипед который умел объединять данные из табличек, но более простой… зато умел с полученной «структуры» раскладывать обратно по таблицам после внесения изменений.

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


// --------  aggregator -----------
// -------- end aggregator --------

То что ваше решение умеет раскладывать обратно по таблицам после внесения изменений это круто. Хотя тот же актив рекорд, то же умеет удобно сохранять данные, но при условии что структура БД не сложная, возможно ваш вариант решает какие-то специфические задачи, было бы интересно взглянуть, если этот код есть на гитхабе.

Мой велосипед давно умер, к сожалению, да и стесняшка я :) но вот что я уяснил, подготовкой данных лучше заниматься максимально на стороне базы, php бывает медленен для этого. ну эт имхо конечно

Да, конечно php медленнее, но тут проблема в том что БД не может отдать мне в рнр выборку со вложенными параметрами, так что выбора особо нет =) Да, есть иерархические запросы, но они мне не вернут в рнр честный древовидный массив. Но несмотря на то, что разбор идет на стороне рнр при правильном подходе никаких тормозов нет, потому что подразумевается, что при больших данных пользователь будет использовать пагинацию, которая возвращает к примеру 100 записей, поэтому разбор происходит мгновенно. Я специально не проверял при скольких значениях будет тормозить, но у меня была выборка из нескольких тысяч, обработалось все в лет. Пагинацию самому описывать не надо, она встроена в GP:


->sql($sql)->pagination(1, 10)->all($options) 
Конструктор where у yii находится на уровне построителя запросов, на этом уровне невозможно написать любой sql запрос, оно и понятно в yii сделали так, что при написании запросов с помощью построителя запросов ты не привязан к БД. А мне нужно писать sql запросы использующие уникальные возможности определенной БД (Oracle).

$model->where(new \yii\db\Expression('SQL CODE'))

Что вы подразумеваете под $model->where( … ). $model тут, это экземпляр модели? Но у моделей нет функции where, или надо самому написать какую-то функцию? Пишите более развернуто. Если вы имеете ввиду построитель запросов, то ->where(new \yii\db\Expression('SQL CODE')) не имеет смысла, т.к. я и так могу написать чистый sql для where. Вот отрывок из документации:


Строковый формат - это лучший выбор для простых условий. Он работает так, будто вы просто пишете SQL запрос.  Например : $query->where('status=1');

Еще раз у меня проблема в том, что есть большие запросы, которые в построитель не впихнуть, внутри запроса может быть много where. Вот схематичный пример:


with tab as
(
select 11 as id1, 22 as id2 from dual
union all
select null, 22 from dual
union all
select 33, 44 from dual
union all
select null, 44 from dual
)

select * from (select * from tab where id2 = 22) t
where t.id1 = 11

В Yii2 я бы мог написать костыльную функцию для генерации where части sql. К примеру:


(new \yii\db\Query())->where('id2 = 22')->createCommand()->sql
// Вернет    SELECT * WHERE id2 = 22

Я мог бы вырезать where часть и затем подставить его в основной запрос. Но, как я уже говорил на тот момент yii был недоступен. Ну и конечно генерация where это ни в коем случае не фишка GP ))) Полезность GP в получении вложенного ответа и автоматическое подключение таблицы, описанное в пункте ‘Многократное объединение с самим собой во имя поиска’.

Верно вы подметили с $model — я имел ввиду построитель запросов.
Я хотел сказать, что запросов умеет работаеть с кастомным текстом

Давайте возьмем за основу ваш пример. Его можно сделать вот так:
$queryBuilder = (new \yii\db\Query())
    ->select('*')
    ->from([
        't' =>
            (new \yii\db\Query())
                ->select('*')
                ->from('tab')
                ->where([
                    'id2' => 22,
                ]),
    ])
    ->where([
        't.id1' => 11,
    ]);
var_dump($queryBuilder->createCommand()->rawSql);

Выдает
SELECT * FROM (SELECT * FROM "tab" WHERE "id2"=22) "t" WHERE "t"."id1"=11


Если в where, from, select, orderBy, groupBy и любых других местах нужно использовать кастомные вещи, то можно сделать это с помощью \yii\db\Expression

Пример:
Задача: нужно сделать поиск по таблице users с использованием оператора LIKE по двум колонкам: name, surname.
Сделать это можем вот так:
$queryBuilder = (new \yii\db\Query())
    ->select('*')
    ->from('users')
    ->where(new \yii\db\Expression('CONCAT_WS(" ", name, surname) LIKE :query', ['query' => '%Вася%']));

Выведет следующее:
SELECT * FROM "users" WHERE CONCAT_WS(" ", name, surname) LIKE '%Вася%'


Можно и так:

$queryBuilder = (new \yii\db\Query())
    ->select('*')
    ->from('users')
    ->where(['LIKE', new \yii\db\Expression('CONCAT_WS(" ", name, surname)'), 'Вася']);

Выведет следующее:
SELECT * FROM "users" WHERE CONCAT_WS(" ", name, surname) LIKE '%Вася%'


Тоже самое можно делать и в select(), и в from(), и в groupBy(), и в orderBy(), и в having() — везде в общем :)

да, едиснтсвенное что не умеет — это with — конструкцию.

Спасибо вам за пояснения, приведенный вами пример с построением вложенных таблиц с помощью yii для меня не новость, хотя сам я никогда так не делал, на мой вкус слишком громоздко. Я многих тонкостей с yii не знаю, но мне кажется, что конструкции с with и union all средствами yii не сделать, может я ошибаюсь. Но самое главное я не вижу смысла писать огромные запросы средствами yii. В моем случае мы намертво привязаны к oracle, поэтому абстрагироваться от базы (при этом целиком привязываясь к yii =) ) не надо. Я приведу средний запрос в нашей конторе:
image
Зачем такие запросы строить через построитель запросов? В моем случае 99% всех задач, связанных с sql, требуют всего 3 вещей: генерации where, сортировку выборки по фильтру и пагинацию. Мне гораздо удобней, быстрее, нагляднее и гораздо проще потом поддерживать код, когда запросы написаны на sql, с небольшими вкраплениями генерации where части. Но я ни в коем случае не спорю, что если у вас простые запросы, то yii может быть удобнее, чем чистый sql.

очень сложный велосипед, с ним не получиться так что бы «сел и поехал», поэтому без тонны обучающего материала ни кто не будет пользоваться этим решением если сталкивается с подобной задачей впервые.
За статью спасибо.

Да, велосипед сложный получился, но это же первая версия =) У меня есть идеи как можно очень сильно все упростить, но это потребует полной переделки, а времени сейчас нет. Возможно потом займусь.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации