LINUX.ORG.RU

Как вы встраиваете SQL в свой код?

 


2

2

Здравствуйте

Есть ли какие-нибудь общепринятые способы встроить SQL в свой код? Писать SQL в виде строк (да порой еще и склеенных с переменными) прямо по ходу кода, как мне кажется, плохой тон. Такое сложно поддерживать и отсутствие подсветки синтаксиса не добавляет удовольствия.

★★★★★

man mensia select, man qlc

anonymous
()

Обычно пишу в коде в строковых переменных. Стараюсь писать так, чтобы можно было легко выделить всё выражение и скопировать в буфер обмена. Если в языке есть многострочные литералы, то совсем хорошо. Если нет — пишу как-то так:

String sql = "" +
        "select a     " +
        "from b       " +
        "where c = d  ";
для выделения нужно, чтобы редактор поддерживал выделение прямоугольного блока текста.

Можно писать в отдельных файлах, но тут большой минус — надо больше щёлкать, чтобы увидеть запрос. Когда исследуешь и редактируешь код, удобней, когда всё, относящееся к делу, в одном месте, нежели раскидано по файлам.

Склеивать с переменными нужно аккуратно. Обычно для этого есть PreparedStatement.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от Deleted

Тоже пришел к такому умозаключению в процессе размышлений (только без тестовых параметров, одни названия выражений)

makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

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

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от Deleted

А если нужно генерировать сложные запросы на основе запросов пользователя? Хранить один большой запрос, некоторые части которого могут отключаться установкой булевого параметра (что-то вроде WHERE ... %4 OR user.email = '%5' ..., где %4 устанавливается в TRUE или FALSE)?

// Это кто мне постинг заблокировал за «провокацию flame»? Это, учтите общественный IP.

anonymous
()
Ответ на: комментарий от robot12

После вакханалии препарсинга исходников из лагеря node.js, подобные практики вызывают обморочный припадок )

makoven ★★★★★
() автор топика
Ответ на: комментарий от anonymous

А если нужно генерировать сложные запросы на основе запросов пользователя?

Это плохой путь т.к. запросы не кешируются планировщиком субд при этом, но можно накрутить свой макроязык (как это с делано в mybatis)

Deleted
()
Ответ на: комментарий от Deleted

А если нет скиллов реализовать парсер подобных файлов на каждом языке, на котором пишешь?

Распарсить

--!Get values
SELECT * FROM "foo";
не проблема. А вот коментарии внутри строки..

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от makoven

А если нет скиллов реализовать парсер подобных файлов на каждом языке, на котором пишешь?

Это примитивная statemachine реагирующая на /* и — в критических случаях можно даже режекспами парсить - синтаксис крайне примитивен и разбирать sql не требуется же

Deleted
()
Ответ на: комментарий от Legioner

Идея с блоками хороша (не только для SQL, а вообще). Надо будет запомнить

makoven ★★★★★
() автор топика

можно такой подход:

деление на логические слои с разным уровнем абстракции и степени «тупости»

прикладной уровень getProduct, ls

мидл-слой select

драйвер-слой prepare bind execute fetch

Наиболее сложная часть - ненавязчивый биндинг, прикладные фильтры, спецификация полей и колонок, вложенные запросы, зависимости от от бд и диалекты (что в общем решаемо)

за основу можно взять такую связку:

prepare

bind

execute

fetch

Кроме fetch, возвращается везде statement сущность

anonymous
()

Для Си - встраиваю SQL в код. Но с использованием спец.библиотеки, которая абстрагирует от API драйвера конкретной DB и диалектов SQL, обеспечивает доступ к колонкам результата по номерам или именам, а также позволяет удобно работать с prepared statements (биндинг либо по именам либо прозрачно в printf-стиле, в последнем случае с проверкой подставляемых типов данных ещё на этапе компиляции).

Sorcerer ★★★★★
()
Ответ на: комментарий от makoven

от хз, я этот парсер писал эдак в 2012 и уже ушел с той конторы - так что не посмотреть сколько оно занимало на яве

Deleted
()
Ответ на: комментарий от makoven

какой еще ассемблер? это pl/sql. ты же не пояснил в какой именно язык надо встраивать.

unt1tled ★★★★
()

Обычно orm, но когда его не хватает - в sql файлах.

holuiitipun
()

Как вы встраиваете SQL в свой код?

<petrosyan>В html/js файлах.</petrosyan>

orm-i-auga ★★★★★
()

Зделал! http://pastebin.com/z8sx8XnF

local stmts = Statements:new("foo.sql", "bar.sql")
--!    Create
CREATE TABLE "Test" ("id" INTEGER PRIMARY KEY, "name" TEXT);

--! Insert
INSERT INTO "Test" VALUES(:id, :name);
makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 1)
Ответ на: комментарий от Deleted

Это плохой путь т.к. запросы не кешируются планировщиком субд

Бутылочных запросов обычно очень мало. А страдать с файликами приходится сразу для всех.

anonymous
()
Ответ на: комментарий от makoven

То-есть, сначала придумали SQL

Если вспомнишь для кого придумали SQL, то может поймешь почему нужен ORM. И почему шаблонизатор для динамических запросов (как некоторые тут предлагают) тот же самый ORM, только в профиль.

anonymous
()
Ответ на: комментарий от anonymous

Ну и плюс как ты предлагаешь фильтры набирать? Как запросы не генерируй — они все мимо плана окажутся.

anonymous
()

В Идее, кстати, SQL подсвечивается и дополняется даже если это переменная-строчка, а не отдельный файл. Так что не развесистые SQL-и лучше сразу в код фигачить. Меньше файлов — больше ясности.

anonymous
()
Ответ на: комментарий от anonymous

Меньше файлов — больше ясности.

То есть максимальная ясность достигается путем склеивания файлов в одну портянку?

anonymous
()
Ответ на: комментарий от Deleted

Это не хранимки. У нас вся логика на pl/sql на оракле.

unt1tled ★★★★
()
Ответ на: комментарий от anonymous

По ссылке особо не читал, но по своему опыту знаю, что план запроса зависит от параметров.

anonymous
()

Строки + placeholder.

Строки + конкатенация.

kachan ★★
()
Ответ на: комментарий от makoven

То-есть, сначала придумали SQL, а потом придумали ORM, чтобы стыдливо прикрывать SQL?

Сначала придумали машинные коды, потом придумали ассемблер, чтобы стыдливо прикрывать машинные коды. Потом придумали Фортран, чтобы стыдливо прикрывать ассемблер. Потом придумали Си, чтобы стыдливо прикрывать Фортран и ассемблер. Потом придумали Си++, чтобы стыдлио прикрывать Си. Потом придумали SQL, чтобы стыдливо прикрывать Си/Си++... Ну и так далее.

KRoN73 ★★★★★
()
Ответ на: комментарий от anonymous

Ну потому обычно и юзают генераторы запросов, некоторые просто берут шаблонизатор типа velocity и прогоняют исходник sql запроса через него, но зачем если есть mybatis

Deleted
()
Ответ на: комментарий от exception13

а если надо анонимную функцию нагенерить из сниппетов по маппингам?

Преждевременная оптимизация — зло. Когда понадобится, тогда и можно будет решать этот вопрос. Никто не запрещает в исключительном случае сделать и прямой SQL-вызов. Поскольку случай исключительный, то на _нормы_ оформления пофиг. У меня есть подобный пример на паре сайтов — просто строкой в коде прописано:

        $this->db()->query("
            UPDATE posts
                SET page = FLOOR((SELECT @rn:= @rn + 1 FROM (SELECT @rn:= -1) s)/{$this->items_per_page()})+1
                WHERE topic_id = {$this->id()}
                    AND is_hidden = 0
                ORDER BY `create_time`, `id`;
        ");

Единичные исключения не отменяют тысячекратно оправданные правила :)

KRoN73 ★★★★★
()
Ответ на: комментарий от KRoN73

Ормами ни разу не ппользовался. Да и SQL-ем не особо до недавнего времени.

Возник вопрос. Есть у меня группа объектов, размазанная по двум базам. Одна база с постоянными данными, другая - с временными (в директории /run). SQL-запрос ATTACH-ит базы, JOIN-ит столбцы и возвращает готовенькие объекты. Как это изобразить в ORM?

makoven ★★★★★
() автор топика
Последнее исправление: makoven (всего исправлений: 2)
Ответ на: комментарий от KRoN73

у меня задача etl/mdm так что тут без хранимок не обойтись. но и клепать 100500 хранимок на каждую модель расточительно. потому и генерация огромной pl/pgsql в DO $...$

exception13 ★★★★★
()
Ответ на: комментарий от makoven

другая - с временными (в директории /run)

Для JOIN'а это пофиг.

Как это изобразить в ORM?

Да также, как и в SQL :) Что-то типа

$news = News::find()
    ->left_join("tmp_visits ON id = news_id")
    ->in('category_id', [1,3,5])
    ->group('news_id')
    ->order('-create_time')
    ->all(10);

Пример приблизительный, как это я делаю у себя. А так, в разных ORM'ах по-разному. Где-то JOIN'ы автоматические исходя из модели, где-то дозагружаются вторым запросом, где-то — просто нет.

Сам не юзал, но пример из Idiorm:

$tweets = ORM::for_table('tweet')
    ->select('tweet.*')
    ->join('user', array(
        'user.id', '=', 'tweet.user_id'
    ))
    ->where_equal('user.username', 'j4mie')
    ->find_many();

Sparrow:

echo $db->from('user')
    ->join('role', array('role.id' => 'user.id'))
    ->select()
    ->sql();

KRoN73 ★★★★★
()
Ответ на: комментарий от exception13

у меня задача etl/mdm так что тут без хранимок не обойтись

Ну так универсальных решений и не бывает :)

KRoN73 ★★★★★
()
Ответ на: комментарий от Legioner

Точно так же делаю. Для переменных либо prepared statements, либо простой String.Format.

ritsufag ★★★★★
()
Ответ на: комментарий от KRoN73

А это точно ОРМ? Выглядит как SQL, обернутый в функции. Я думал ОРМ это что-то типа

pigs.fetch();
pigs[1].name = "Bacon";
pigs.save();
makoven ★★★★★
() автор топика
Ответ на: комментарий от makoven

А это точно ОРМ?

Это пример join'ов при условной загрузке массивов объектов.

Я думал ОРМ это что-то типа

А вот потом с этими объектами и работают таким образом. Например (но для простоты уже без join'ов, тем более, что в случае простой «пристыковки» параллельных таблиц у меня это в модели скрывается):

$topic = Topic::load($request->get('topic_id'));

$post = Post::create([
    'user_id'  => $me->id(),
    'topic_id' => $topic->id(),
    'title'    => $request->get('title'),
    'text'     => $request->get('text'),
]);

$topic->set_last_post_id($post->id());
$topic->set_last_user_name($me->nick());

KRoN73 ★★★★★
()
Последнее исправление: KRoN73 (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.