Работа со строками sql: MS SQL Server и T-SQL

Курс SQL & Hibernate — Лекция: Строковые функции

SQL & Hibernate

4 уровень
,
4 лекция

Открыта

Список строковых функций

Больше функций, чем у даты и времени, — только у типа String. Который в SQL задается типами CHAR(n) и VARCHAR(n). Вспомним самые популярные из них:

ФункцияОписание
1LENGTH(str)Возвращает длину переданной строки в байтах
2CHAR_LENGTH(str)Возвращает длину переданной строки в char’ах
3LOCATE(substr,str),Ищет подстроку в строке аналогично методу indexOf()
4LOCATE(substr,str,pos)Ищет подстроку в строке, начиная с символа pos
5CONCAT(str1,str2,…)Склеивает несколько строк
6SUBSTR(), SUBSTRING()Возвращает подстроку, заданную диапазоном символов
7LOWER(str)Преобразует строку в нижний регистр
8UPPER(str)Преобразует строку в верхний регистр
9REPLACE()Заменяет подстроку в строке
10MATCH()Проверяет совпадение строки заданному шаблону
11TRIM(str)Обрезает пустые символы в начале и в конце строки
12LTRIM(str)Обрезает пустые символы в начале строки
13RTRIM(str)Обрезает пустые символы в конце строки
14TO_BASE64(str)Преобразует строку в Base64
15FROM_BASE64(str)Преобразует строку из Base64

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

Преобразуем строку

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

Поэтому я просто приведу табличку с несколькими примерами.

#ЗапросРезультат
1SELECT LENGTH(‘text’)4
2SELECT LENGTH(‘Привет’)12
3SELECT LOWER(‘Привет’)привет
4SELECT UPPER(‘Привет’)ПРИВЕТ
5SELECT SUBSTR(‘Привет’, 2, 3)рив
6SELECT SUBSTR(‘Привет как дела?’, 8)как дела?

Функции работают ожидаемо, как и аналогичные им функции из JDK.

Единственный нюанс: в первой строке результат 4, а не 8. Все дело в том, что для кодировки латинских символов в запросе используется 1 байт (кодировка ASCII).
Но если будешь работать с данными из базы данных, то длина строки будет зависеть от настроек кодировки базы данных. Тебя ждет много сюрпризов при работе с базой данных 🙂

Сложные действия со строками

Ну и давай разберем более сложные вещи при работе со строками. Что бы такое придумать…

Давай отобразим задания из таблицы task, и если deadline задания уже прошёл, то добавим к описанию задания слово EXPIRED!

Звучит интересно. Хотя сложные условия мы еще не учили, так что давай немного упростим задачу. Просто напишем запрос, который отобразит список прошедших задач, но к названию обязательно добавит слово “EXPIRED!”.

Для этого нам придется использовать функцию CONCAT:

   SELECT CONCAT( 'EXPIRED! ', name) FROM task 
   WHERE deadline < CURDATE() 

Результат этого запроса будет таким:

concat(‘EXPIRED! ‘, name)
EXPIRED! Исправить багу на фронтенде

Рекомендация. Если тебе нужно просто преобразовать данные немного к другому виду, то это можно сделать и на уровне Java-кода. Но если ты хочешь использовать функции работы со строками на стороне SQL-сервера( внутри WHERE), то без них тебе точно не обойтись.

Этот веб-сайт использует данные cookie, чтобы настроить персонально под вас работу сервиса. Используя веб-сайт, вы даете согласие на применение данных cookie. Больше подробностей — в нашем Пользовательском соглашении.

Дополняя SQL. Часть 2. Оптимизация работы со строками и открытия файлов / Хабр

Публикую на Хабр оригинал статьи, перевод которой размещен в блоге Codingsight.

Что будет в этой статье?


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

Для ленивых основные тезисы первой статьи:

  • Мы делаем линейку IDE для СУБД MySQL, SQL Server, Oracle, PostgreSQL
  • Это настольное приложение на .NET стеке со всеми вытекающими
  • Много функций завязаны на анализ SQL кода. Используем для этого сильно доработанный ANTLR


По мере публикации буду добавлять ссылки на следующие части:

Часть 1. Сложности парсинга. Истории о доработке ANTLR напильником
Часть 2. Оптимизация работы со строками и открытия файлов
Часть 3. Жизнь расширений для Visual Studio. Работа с IO. Необычное использование SQL
Часть 4. Работа с исключениями, влияние данных на процесс разработки. Использование ML.NET

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

Крутые

велосипеды решения

OutOfMemory в Visual Studio и постпроцессинг ANTLR парсера


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

Почему? А потому, что стоило неудачно нажать F11(step-into) при отладке, попасть в файл парсера и Visual Studio просто схлопывалась. Подключившись одной VS к другой мы выяснили, что она падает с OutOfMemoryException во время анализа этого файла. Файл парсера состоял из более чем 200 тысяч строк кода. К сожалению, отладка парсера это неотъемлемая часть работы. Мы не могли просто не смотреть туда. К счастью C# поддерживает partial-классы. Таким образом уже сгенерированный парсер, мы анализировали регулярными выражениями и раскладывали по нескольким файлам. В результате удалось сократить размер основного файла примерно наполовину, после чего Visual Studio работала безупречно.

Лексический анализ без substring до Span API


В .NET недавно появилось API для работы с подстроками и подмассивами без лишних аллокаций. К сожалению, задача оптимизировать лексический анализ появилась у нас задолго до этого. Задача лексического анализа — определение границ слов и их сопоставление со словарем — классификация. Изначально эта задача была решена у нас в лоб: цикл ходил по строке, встречая последовательность букв, шел до разделителя, обрезал при помощи Substring, приводил строку в нижний регистр, искал в словаре. Если слово было найдено, то лексер возвращал его индекс, иначе считал это слово идентификатором объекта. Это немного упрощенное описание алгоритма, чтобы быстро передать суть, не вдаваясь в подробности.

Результаты профилировки показали, что немалую часть времени занимали Substring и ToLower, в то время как поиск по словарю работал невероятно быстро. Было необходимо как-то оптимизировать это бутылочное горлышко. У нас получилось довольно круто прокачать метод ToLower используя тот факт, что в ключевых словах была только латиница. Результат был заметным, но недостаточным. Внезапно появилась идея разложить словарь в 26-ричное дерево, где индекс в массиве под-услов соответствует положению буквы в английском алфавите. Проходя по строке мы совершаем навигацию по такому дереву. Если на момент окончания слова значение номера токена в текущем узле отлично от нуля, значит в языке есть соответствующий keyword, если нет, то вероятно, это идентификатор пользовательского объекта. Такой трюк ускорил лексический разбор примерно на 30%.

Было бы интересно вернуться к оптимизации лексера с новыми знаниями и новыми инструментами. Уверен оттуда можно выжать еще немного. Например, где-то спустя пол года после решения этой задачи стала набирать популярность библиотека BenchmarkDotNet. Она органично влилась в workflow любой оптимизации: после того как при помощи профилировщика найдено бутылочное горлышко, создается бенчмарк, метод переписывается много раз, пока не достигается необходимый результат. Что удивляет, так это то, что результаты часто очень не очевидны.

Фоновый лексинг во время открытия файла


Я уже писал, что люди работающие с SQL часто работают с большими файлами. Чего уж там, парсер на CSharp в 200 тысяч строк это нечто из ряда вон выходящее, с другой стороны дамп базы данных на полмиллиона никого даже не удивит. Встраиваясь в VS и SSMS мы не лезем в нативные механизм подсветки кода, но в наших standalone тулах нам приходится решать эту задачу. К счастью, мы работаем в 64 битном адресном пространстве и можем открыть даже очень большие файлы, если у пользователя окажется достаточно оперативной памяти. Только вряд ли кто-то будет рад ждать открытия такого файла слишком долго, верно? В одной из версий нам удалось существенно ускорить открытие файлов с помощью нескольких хитрых трюков. Раскраска текста происходит на основе лексического анализа. Эта операция, как правило, существенно медленнее чтения текста с диска. В чем же трюк? В одном потоке начинается чтение текста из файла, во второй его лексический разбор. Лексер запрашивает текст построчно и если он запросит строку, которой еще нет, то повиснет в ожидании. По этому принципу работает BlockingCollection<T> из BCL, а алгоритм является типичным применением многопоточного паттерна Producer-Consumer. Редактор, работающий в главном потоке запрашивает данные о первой раскрашенной строчки, если она недоступна, то повисает в ожидании. По сути producer-consumer и blocking-collection применены дважды:

  1. Чтение из файла — Producer, лексер — Consumer
  2. Лексер уже является Producer, а текстовый редактор — Consumer


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

Неочевидные победы

Неоднозначная оптимизация: частичный лексический анализ


Синтаксический анализ разделяют на две части:

  • входящий поток символов разбивается на слова(token’ы) в рамках правил языка — это называют лексическим анализом;
  • парсер идет уже по потоку token’ов, проверяя на соответствие правилам, часто строит синтаксическое дерево.


Работа со строками традиционно считается дорогостоящей операцией. У нас была идея как это оптимизировать: не делать полный лексический разбор текста каждый раз, а заново проанализировать лишь изменившуюся часть. Тут может возникнуть вопрос, а что делать с многострочными конструкциями, вроде блочных комментариев или строк? Для этого был интересный трюк — для каждой строки хранилось состояние для конца строки: “нет многострочных токенов” = 0, “начался блочный комментарий” = 1, “начался многострочный строковый литерал” = 2. Лексический разбор проводится от измененного участка и до того как не сойдется состояние на конце строки.

Звучит неплохо, не так ли? Так что же такого неочевидного в этой истории? Ей место в блоке с крутыми трюками. Сперва мы попробовали упаковать результаты разбора в легковесные промежуточные структуры: 2 байта на смещение в строке, 2 байта на тип токена, 2 байта на длину и сложить их в объект. На основе таких структур, на лету, для парсера создавались полноценные экземпляры класса Token из ANTLR. Померяли все, прирост производительности оказался менее 5%. Результаты профилировки стали еще более размазанными, не было видно никакого бутылочного горлышка, разве что оператор new занимал довольно много времени. С большой грустью ушли домой, на выходные. Как это часто бывает, когда всю неделю плотно работал над какой-то задачей, не доведя ее до логического решения, она продолжает вращаться в голове. В понедельник появилась идея отказаться от промежуточных структур и хранить сразу объекты Token. Идя на это мы понимали, что это займет больше оперативной памяти, чем легковесные структуры. Мы понимали, что число занимает в памяти меньше строки, но не удосужились в тот момент все тщательно просчитать. В этом решении была еще одна проблема: крайне неудобно следить за номерами строк в таких структурах, а номер строки является обязательным атрибутом ANTLR Token, ведь при вставки или удалении строки придется обновлять номера строк в каждом токене, что идет ниже. Решением этой проблемы стало проставление номера строки на лету, перед выдачей токена парсеру. Мы провели некоторые тесты, получили прирост производительности составил 15-25%. Здесь необходимо пояснить, что фактический прирост даже больше. Некоторые функции, например Quick Info, чья работа была завязана лишь на лексический анализ работали мгновенно. Quick Info — функциональность доступная в каждом продукте линейки, это та самая всплывающая подсказка с информацией об объекте при наведении курсора на его идентификатор в скрипте. Выигрыш оказывался фактически больше, когда требовалось совершить несколько проходов по токенам.

Количество оперативной памяти необходимое для такого отражения текста оказалось существенно больше чем мы ожидали. ANTLR Token состоял из: точки начала — 8 байт, точки конца — 8 байт, ссылки на текст слова — 4 или 8 байт, не говоря уже о самой строке, ссылки на текст документа — 4 или 8 байт, типа токена 4 байта. Важно сказать, что чаще всего токены не хранили свой текст, а лишь высчитывали его по необходимости, лишь в некоторых случаях текст кешировался. Кроме того это был класс, а не структура, а это означает еще ряд расходов. Общий размер всего объекта получился в несколько раз больше изначального размера текста. Поняли мы это значительно позже. Мало кто ожидает большого перерасхода памяти от класса с несколькими int`овыми полями. В теории, на скрипте с крайне длинными именами объектов и литералами мы могли бы получить даже какой-то выигрыш по памяти. Примерно с 30 символов на слово, такой способ представления скрипта даже становится выгодным.

Какие выводы? С одной стороны выигрыш производительности изначально получился ниже чем хотелось получить. Бутылочное горлышко казалось очевидным. Сфокусировались на производительности, получили перерасход по памяти, там где это не было очевидно. Нельзя сказать, что мы этого совсем не ожидали, но мы не предположили, ведь мы даже изначально пытались использовать легковесные структуры, вместо классов. Заменяя их полноценными объектами мы осознанно шли на дополнительный расход памяти, ради получения выигрыша в производительности. Проблема в том, что мы не сели и скрупулезно не посчитали сколько будет занимать такой класс. Но о том, что кучка int’ов может съесть так много памяти задумываешься, все таки не часто. К счастью, это послужило для нас важным уроком и теперь каждая оптимизация производительности заканчивается снятием профиля памяти и наоборот.

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

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

Заключение


Промежуточные итоги могут быть следующими:

  • Проблемы в работе инструментов разработчика могут быть неприятны и существенно мешать всему процессу. Нужно находить их проблемы и решать как можно быстрее
  • Новые версии .NET дают нам новые крутые возможности. Возможно есть смысл вернуться к задачам решенным в прошлом и попробовать зайти с новыми инструментами
  • Любая оптимизация состоит из двух частей: поиск бутылочного горлышка, для этого отлично подходят профилировщике и его оптимизация, для этого удобно создавать бенчмарки
  • Не стоит оптимизировать без тщательного профилирования, даже если вы знаете где узкое место, полезно понять максимально возможный потенциал для оптимизации
  • Когда счет идет на миллионы объектов, каждый байт решает
  • После успешной оптимизации производительности, снимите профиль использования оперативной памяти и наоборот

Работа со строками SQL

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

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

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

Строки присущи вашим данным — это поля имени, которые кто-то вводит при регистрации учетной записи, они представляют товар, который кто-то купил в вашем интернет-магазине, они описывают адрес покупателя и т. д.

Чтобы немного формализовать, строковый тип — это слово или комбинация символов, которые обычно заключаются в одинарные кавычки (например, «Jaffle Shop», «1234 Shire Lane», «Plan A»).

Чаще всего, когда вы работаете со строками в модели БДТ или запросе, вы:

  • Изменение регистра (увеличение/уменьшение) для создания некоторого стандарта для столбцов строкового типа в хранилище данных
  • Объединение строк для создания более надежных, единообразных или описательных строковых значений
  • Удаление вложенных объектов JSON или более сложных структурированных данных и преобразование этих значений в явные строки
  • Преобразование столбца другого типа в строку для лучшей совместимости или удобства использования в инструменте BI
  • Фильтрация запросов по определенным строковым значениям
  • Создание нового типа строкового столбца на основе инструкции CASE WHEN для группирования данных по
  • Разделение строки на подстроку

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

Строки в примере запроса

 select 
date_trunc('month', order_date)::string as order_month,
round(avg(amount)) as avg_order_amount
from {{ ref('orders') }}
где статус не в ('returned', 'return_pending')
сгруппировать по 1

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

9 0057

order_month avg_order_amount
01.01.2018 18
01.02.2018 15
01.03.2018 18
01.04.2018 17

Snowflake, Databricks, Google BigQuery и Amazon Redshift поддерживают строковый тип данных. У них могут быть немного разные подтипы для строк; некоторые хранилища данных, такие как Snowflake и Redshift, поддерживают типы текстовых, символьных и символьных строк, которые обычно отличаются по длине в байтах по сравнению с общим типом строки.

Опять же, поскольку большинство столбцов строкового типа являются неотъемлемой частью ваших данных, вы, вероятно, будете в порядке, используя универсальный varchar или строки для преобразования, но никогда не помешает прочитать документацию, относящуюся к поддержке строк вашего хранилища данных!

psycopg2.sql — Состав строки SQL — документация Psycopg 2.9.6

Новое в версии 2.7.

Модуль содержит объекты и функции, полезные для динамической генерации SQL,
удобным и безопасным способом. Идентификаторы SQL (например, имена таблиц и
поля) не могут быть переданы в метод execute() , такой как запрос
аргументы:

 # Это не сработает
имя_таблицы = 'моя_таблица'
cur.execute("вставить в %s значения (%s, %s)", [table_name, 10, 20])
 

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

 # Это работает, но не оптимально
имя_таблицы = 'моя_таблица'
курс.выполнить(
    "вставить в значения %s (%%s, %%s)" % имя_таблицы,
    [10, 20])
 

Этот вид работает, но это ожидание несчастного случая: имя таблицы
может быть недопустимым литералом SQL и нуждаться в кавычках; еще более серьезным является
проблема безопасности в случае, если имя таблицы получено из ненадежного источника.
имя должно быть экранировано с помощью quote_ident() :

 # Это работает, но не оптимально
имя_таблицы = 'моя_таблица'
курс.выполнить(
    "вставить в значения %s (%%s, %%s)" % ext.quote_ident(table_name, cur),
    [10, 20])
 

Теперь это безопасно, но несколько случайно. В случае, если по какой-то причине это
необходимо включить значение в строку запроса (как и в значении)
правило слияния все еще отличается ( адаптировать() должно быть
использовал…). Это также все еще относительно опасно: если quote_ident()
где-то забыл, программа обычно будет работать, но в итоге вылетит
при наличии имени таблицы или поля, содержащего символы для экранирования,
или представит потенциально слабую сторону, которую можно использовать.

Объекты, предоставляемые модулем psycopg2.sql , позволяют генерировать SQL
операторы на лету, четко разделяя переменные части оператора
из параметров запроса:

 из psycopg2 импортировать sql
курс.выполнить(
    sql.SQL("вставить в {} значения (%s,%s)")
        .format(sql.Идентификатор('my_table')),
    [10, 20])
 

Использование модуля

Обычно шаблон запроса следует выражать в виде экземпляра SQL .
с {} 9Заполнители в стиле 0044 и используйте format() для слияния переменной
части в них, все из которых должны быть Composable подклассов. Вы все еще можете
иметь заполнителя в стиле %s в запросе и передавать значения в
execute() : такие заполнители значений не будут затронуты
формат() :

 запрос = sql.SQL("выберите {поле} из {таблицы}, где {pkey} = %s").format(
    поле = sql.Идентификатор («мое_имя»),
    таблица = sql.Идентификатор ('some_table'),
    pkey=sql. Идентификатор('id'))
 

Результирующий объект предназначен для прямой передачи в методы курсора, такие как
execute() , executemany() , copy_expert() , но можно
также можно использовать для составления запроса в виде строки Python, используя
метод as_string() :

 cur.execute (запрос, (42,))
 

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

 запрос = sql.SQL("выберите {поля} из {таблицы}").format(
    поля = sql.SQL(',').join([
        sql.Идентификатор('поле1'),
        sql.Идентификатор('поле2'),
        sql.Идентификатор('поле3'),
    ]),
    таблица = sql.Идентификатор ('some_table'))
 

объекты sql

Объекты sql находятся в следующей иерархии наследования:

Composable : базовый класс, предоставляющий общий интерфейс

|__ SQL : буквенный фрагмент SQL-запроса

|__ Идентификатор : идентификатор PostgreSQL или последовательность идентификаторов, разделенных точками

|__ Литерал : a значение жестко закодировано в запросе

|__ Заполнитель : заполнитель %s в стиле , значение которого будет добавлено позже, например. by execute()

|__ Составной : последовательность из Составных экземпляров.

класс psycopg2.sql.Composable ( в оболочке )

Абстрактный базовый класс для объектов, которые можно использовать для составления строки SQL.

Компонуемые объекты могут быть переданы непосредственно в execute() ,
executemany() , copy_expert() вместо запроса
нить.

Составные объекты могут быть объединены с помощью оператора + : результат
будет Composed 9Экземпляр 0044, содержащий объединенные объекты. Оператор
* также поддерживается с целочисленным аргументом: результатом является
Составленный экземпляр , содержащий левый аргумент, повторяющийся столько раз, сколько
просил.

as_string( контекст )

Возвращает строковое значение объекта.

Параметры:

контекст ( соединение или курсор ) — контекст, в который будет оцениваться строка.

Метод автоматически вызывается execute() ,
executemany() , copy_expert() если Composable
передается вместо строки запроса.

класс psycopg2.sql.SQL ( строка )

A Composable , представляющий фрагмент оператора SQL.

SQL предоставляет методы join() и format() , полезные для создания шаблона
где объединить переменные части запроса (например, поле или таблицу
имена).

Строка не подвергается экранированию, поэтому она не подходит для
представлять идентификаторы или значения переменных: вы должны использовать его только для передачи
постоянные строки, представляющие шаблоны или фрагменты операторов SQL; использовать
другие объекты, такие как Identifier или Literal для представления переменной
части.

Пример:

 >>> query = sql.SQL("выберите {0} из {1}").format(
... sql.SQL(', ').join([sql.Identifier('foo'), sql.Identifier('bar')]),
... sql.Идентификатор('таблица'))
>>> print(query.as_string(conn))
выберите "foo", "bar" из "table"
 
строка

Строка, обернутая объектом SQL .

формат( *args , **kwargs )

Объединить компонуемых объектов в шаблон.

Параметры:
  • args ( Composable ) — параметры заменить на нумерованные
    ( {0} , {1} ) или автоматически нумерованные ( {} ) заполнители

  • kwargs ( Composable ) — параметры заменить на named ( {имя} )
    заполнители

Возвраты:

объединение строки SQL с замененными заполнителями

Тип возврата:

Составной

Метод аналогичен методу Python str. format() : строка
шаблон поддерживает автоматическую нумерацию ( {} ), пронумерованный ( {0} ,
{1} …) и именованные заполнители ( {имя} ) с позиционным
аргументы, заменяющие пронумерованные заполнители, и ключевые слова, заменяющие
названные. Однако модификаторы-заполнители ( {0!r} , {0:<10} )
не поддерживаются. Только Composable объекта могут быть переданы в
шаблон.

Пример:

 >>> print(sql.SQL("выбрать * из {}, где {} = %s")
... .format(sql.Identifier('люди'), sql.Identifier('id'))
... .as_string(соедин.))
выберите * из "людей", где "id" = %s
>>> print(sql.SQL("выберите * из {tbl}, где {pkey} = %s")
... .format(tbl=sql.Identifier('люди'), pkey=sql.Identifier('id'))
... .as_string(соедин.))
выберите * из "людей", где "id" = %s
 
присоединиться ( последовательность )

Присоединение к последовательности Составной .

Параметры:

seq (итерируемый из Composable ) — элементы для соединения.

Используйте строку объекта SQL для разделения элементов в seq .
Обратите внимание, что объекты Composed также являются повторяемыми, поэтому их можно использовать как
аргумент в пользу этого метода.

Пример:

 >>> отрывок = sql.SQL(', ').join(
... sql.Identifier(n) для n в ['foo', 'bar', 'baz'])
>>> print(snip.as_string(conn))
"фу", "бар", "баз"
 
класс psycopg2.sql.Идентификатор ( *строки )

A Composable , представляющий идентификатор SQL или последовательность, разделенную точками.

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

Пример:

 >>> t1 = sql.Идентификатор("foo")
>>> t2 = sql.Identifier("ba'r")
>>> t3 = sql.Идентификатор('ba"z')
>>> print(sql.SQL(', ').join([t1, t2, t3]).as_string(conn))
"фу", "ба'р", "ба" "з"
 

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

Пример:

 >>> запрос = sql.SQL("выберите {} из {}").format(
... sql.Идентификатор("таблица", "поле"),
... sql.Идентификатор ("схема", "таблица"))
>>> print(query.as_string(conn))
выберите "таблица"."поле" из "схемы"."таблица"
 

Изменено в версии 2.8: добавлена ​​поддержка нескольких строк.

строки

Кортеж со строками, обернутыми идентификатором .

Новое в версии 2.8: предыдущие версии имели только атрибут строки . Атрибут
все еще существует, но устарел и будет работать, только если
Идентификатор содержит одну строку.

класс psycopg2.sql.Literal ( в оболочке )

A Composable , представляющий значение SQL для включения в запрос.

Обычно вы захотите включить заполнители в запрос и передать значения
as execute() аргумента. Однако, если вам действительно нужно
включите буквальное значение в запрос, вы можете использовать этот объект.

Строка, возвращаемая as_string() , соответствует нормальной адаптации
правила для объектов Python.

Пример:

 >>> s1 = sql.Literal("foo")
>>> s2 = sql.Literal("ba'r")
>>> s3 = sql.Literal(42)
>>> print(sql.SQL(', ').join([s1, s2, s3]).as_string(conn))
'фу', 'ба''р', 42
 
завернутый

Объект, обернутый литералом .

класс psycopg2.sql.Placeholder ( имя = нет )

A Composable , представляющий заполнитель для параметров запроса.

Если имя указано, создайте именованный заполнитель (например, %(name)s ),
в противном случае создайте позиционный заполнитель (например, %s ).

Объект полезен для создания SQL-запросов с переменным числом
аргументы.

Примеры:

 >>> имена = ['foo', 'bar', 'baz']
>>> q1 = sql.SQL("вставить в таблицу ({}) значения ({})").format(
... sql.SQL(', ').join(map(sql.Identifier, имена)),
... sql.SQL(', ').join(sql.Placeholder() * len(names)))
>>> печать (q1.as_string (соедин.))
вставить в таблицу ("foo", "bar", "baz") значения (%s, %s, %s)
>>> q2 = sql.SQL("вставить в таблицу ({}) значения ({})").format(
... sql.SQL(', ').join(map(sql.Identifier, имена)),
... sql.SQL(', ').join(map(sql.Placeholder, имена)))
>>> печать (q2.as_string (соедин.))
вставить в таблицу ("foo", "bar", "baz") значения (%(foo)s, %(bar)s, %(baz)s)
 
имя

Имя Заполнителя .

класс psycopg2.