Язык программирования самого высокого уровня содержит всего несколько команд для управления программистами
Показаны сообщения с ярлыком MS SQL Server. Показать все сообщения
Показаны сообщения с ярлыком MS SQL Server. Показать все сообщения
02 февраля 2026
20 августа 2025
MS SQL Server. Таблицы оптимизированные для памяти и пропажа места на диске
К нам в поддержку обратился клиент с ошибкой "MAT/PIT export/import encountered a failure for memory optimized table or natively compiled stored procedure with object ID 1873539326 in database ID 5. The error code was 0x80030070." в приложении работающем с MS SQL Server.
Так как в тексте ошибки упомянута таблица оптимизированная для памяти, то моя первая мысль была, что на сервере недостаточно памяти или она глюканула. Поиск описания ошибки по коду 0x80030070 вывел на STG_E_MEDIUMFULL "There is insufficient disk space to complete operation", а потом на ERROR_DISK_FULL 112 (0x70) "There is not enough space on the disk". Действительно, как мне потом написали, у клиента "всё починилось добавлением места". Как связаны таблицы оптимизированные для памяти и недостаток места на диске для завершения операции?06 июня 2024
Преобразование JSON-строки в тип дата/время используя SQL
Согласно стандарту ECMA-404. The JSON Data Interchange Syntax в JSON нет типа для хранения даты и времени. В каком виде они будут закодированы в каждом конкретном JSON-файле определяет его автор. Я встречал два варианта:
- Целое число содержащее UNIX-время (UNIX-time или POSIX-time), которое используется в UNIX и других POSIX-совместимых операционных системах, и определяет количество секунд, прошедших с полуночи (00:00:00 UTC) 1 января 1970 года.
- Строка. Формат строки зависит от фантазии автора файла, но обычно используется стандарт ISO 8601, который представляет дату и время в универсальном формате, легко читаемом как людьми, так и машинами.
29 февраля 2024
Уникальные индексы и NULL
Согласно стандарту ANSI SQL, NULL – это специальное значение или псевдозначение, которое используется для обозначения отсутствия в поле базы данных какого-либо значения. О таком поле можно сказать, что оно имеет неопределенное значение или то, что оно пустое. Стандарт регламентирует, что NULL не равен NULL даже для полей с одинаковым типом данных. Хотя при этом строки, содержащие в поле NULL, группируются вместе при использовании DISTINCT или GROUP BY. В определении уникального ограничения SQL-92 ни слова не говорит про NULL: "A unique constraint is satisfied if and only if no two rows in a table have the same non-null values in the unique columns". Вероятно, это означает, что оно должно рассматривать каждый NULL, как уникальное значение. Как это реализовано в различных СУБД?
20 ноября 2023
MS SQL Server. Работа с данными от имени другого пользователя
Я уже писал об использовании EXECUTE AS в MS SQL Server. Тогда я использовал "WITH EXECUTE AS OWNER" для изменения контекста безопасности на владельца триггера и "EXECUTE AS CALLER" для изменения контекста безопасности в коде триггера на пользователя, вызвавшего модуль. Хочу поговорить о вызове "EXECUTE AS" с указанием имени пользователя.
23 октября 2023
MS SQL Server. Запись данных из триггера в другую базу данных
Представим ситуацию, в которой на сервере MS SQL Server есть две базы данных. С первой базой через свою информационную систему работают пользователи. Во вторую базу для обмена с другой системой выгружаются "итоговые данные, подписанные руководством". Самый простой вариант – это создать триггер, который после подписи будет копировать данные из таблицы первой базы данных во вторую.
28 июля 2023
Новый способ получения OUTPUT-значения после DML операции MS SQL Server в FireDAC Delphi 12
Так получилось, что с периодичностью в два года я пишу о получении в программе значения первичного ключа, который сгенерирован СУБД при добавлении в таблицу новой строки. В 2019-м я писал об этом для UniDAC, потом в 2021-м для FireDAC. Разработчики Delphi 12 предоставили повод написать об этом и в 2023-м. В FireDAC для MS SQL Server, по аналогии с PostgreSQL и Firebird/InterBase, добавлена возможность получения OUTPUT-значения после DML операции с помощью параметров.
12 июня 2023
Сколько строк обработал оператор DML?
После выполнения оператора DML модифицирующего данные иногда бывает необходимо узнать, сколько строк им было обработано. Это может быть полезно, например для определения успешности выполнения оператора или для ведения журнала операций. Каждая СУБД реализует такую функциональную возможность по-своему.
04 апреля 2023
PostgreSQL. Корректировка следующего значения полей SMALLSERIAL, SERIAL и BIGSERIAL
У PostgreSQL, как и у многих других СУБД, есть возможность создавать в таблицах автоинкрементные столбцы. Для этого предназначены типы данных SMALLSERIAL, SERIAL и BIGSERIAL. К сожалению, авторы PostgreSQL не сделали никаких ограничений на прямую запись в столбцы этих типов. С одной стороны – это удобно. В таблицу можно записать данные, у которых уже есть значения для этого столбца. Но с другой стороны – это большая проблема. Такие действия могут привести к дублированию или к ошибке, когда позже при обычной вставке новой записи в таблицу СУБД попытается заполнить поле автоматически. Для сравнения, можно привести как продуманно это реализовано в MS SQL Server. Что бы записать значение в столбец, помеченный как IDENTITY, нужно это разрешить специальной командой "SET IDENTITY_INSERT": вызываем "SET IDENTITY_INSERT имя_таблицы ON", вставляем нужные записи и вызываем "SET IDENTITY_INSERT имя_таблицы OFF". При этом СУБД сама скорректирует текущее значение счетчика на максимальное значение столбца. Для PostgreSQL эту корректировку надо произвести вручную.
29 марта 2023
MS SQL Server. Управление контекстом безопасности подключения к связанным серверам
Механизм связанных серверов MS SQL Server позволяет реализовать распределенные базы данных, которые работают с данными в других базах данных. "Связаться" можно с любым источником данных, для которого существует возможность подключения к нему с использованием OLE DB. Есть два шага обеспечения безопасности при подключении к удаленной базе данных связанного сервера:
- сопоставить имена пользователей локального сервера MS SQL Server с именами пользователей удаленного сервера;
- указать, как связанный сервер должен обрабатывать подключение пользователей, имена которых не сопоставлены.
21 октября 2021
FireDAC vs UniDAC. Получение значения первичного ключа новой строки
Два года тому назад я писал о получении в программе значения первичного ключа, который сгенерирован СУБД при добавлении новой строки в таблицу. Мои примеры вызова INSERT с модификатором RETURNING (или OUTPUT в случае MS SQL Server) были с использованием библиотеки для доступа к базам данных UniDAC. Давайте посмотрим, как реализована эта возможность в библиотеке FireDAC, которая уже много лет входит в поставку Delphi и C++Builder.
22 сентября 2021
MS SQL Server. Получение из файловой системы списка папок и файлов
Иногда работа с базами данных подкидывает не стандартные задачи. Например, недавно мне в скрипте MS SQL Server понадобилось получить из файловой системы список папок и файлов. Мои попытки сделать это через объект Scripting.FileSystemObject потерпели неудачу. Его метод GetFolder по имени папки возвращает объект Folder, у которого есть свойства SubFolders/Files содержащее списки вложенных папок и файлов. Но проблема в том, что эти списки – это коллекции, элементы которых в VBA можно перебрать в цикле "For Each File in Folder.Files", а из скрипта T-SQL к их элементам можно обратиться только по имени папки/файла (exec sp_OAMethod @objItems, N'Item("FileName.txt")', @objItem out). То есть для получения списка папок и файлов объект Scripting.FileSystemObject не подходит. Поиск в интернете позволил мне сформулировать 4 различные способа решения этой задачи.
08 сентября 2021
Фиксим "There is insufficient system memory in resource pool 'internal' to run this query" при запуске MS SQL Server
Вчера MS SQL Server преподнес мне сюрприз. При создании новой базы данных он выдал ошибку "There is insufficient system memory in resource pool 'internal' to run this query" и "умер" – сервис SQL Server не запускался, а в ERRORLOG сыпались ошибки:
Msg 701, Level 17, State 130, Server XYZ, Line 1 There is insufficient system memory in resource pool 'internal' to run this query.
15 апреля 2021
Сортировка по текстовому полю содержащему комбинацию букв и цифр
Сортировка результата SQL запроса – это то, с чем программисты сталкиваются постоянно. Обычно СУБД при сортировке текстовых полей для сравнения строк использует лексикографический порядок. Согласно Википедии, он означает, что слово X предшествует слову Y (X < Y), если:
- либо слово X является началом слова Y (например, "МАТЕМАТИК" < "МАТЕМАТИКА");
- либо первые m символов этих слов совпадают, а m+1-й символ слова X меньше m+1-го символа слова Y (например, "АБАК" < "АБРАКАДАБРА", так как первые две буквы у этих слов совпадают, а третья буква у первого слова меньше, чем у второго).
| Лексикографический порядок | Естественный порядок |
| a12 | a2a |
| a22 | a2b |
| a2a | a3a2 |
| a2b | a3a2a |
| a30z | a12 |
| a3a2 | a22 |
| a3a2a | a30z |
18 февраля 2021
MS SQL Server. Преобразование из ASCII в HEX и обратно
Попросили меня написать скрипт, который конвертировал данные из одной таблицы в другую. При этом одно из текстовых полей нужно "привести к верхнему регистру, взять символы в обратном порядке и преобразовать их из ASCII в HEX". Например, строка "XYZ" должна превратиться в "5A5958". Привести к верхнему регистру и взять символы в обратном порядке – это делают встроенные строковые функции UPPER и REVERSE. Но, преобразование из ASCII в HEX поставило меня в тупик. Гугл мне в помощь!
31 января 2021
Быстрое заполнение нового столбца таблицы
Недавно мне дали скрипт для обновления структуры базы данных на MS SQL Server. В нем было полно блоков, которые добавляли в таблицу столбец, заполняли его в существующих строках одинаковым значением и делали NOT NULL:
alter table MyTable add FIELD1 int null go update MyTable set FIELD1 = 1 go alter table MyTable alter column FIELD1 int not null goЧто будет, если количество строк в таблице измеряется не сотнями или тысячами, а миллионами или десятками миллионов?
08 октября 2020
Табличные переменные в динамическом SQL
Табличные переменные являются одной из интересных возможностей MS SQL Server. Эта удобная альтернатива временным таблицам, которую можно использовать для хранения небольших наборов данных в виде строк таблицы. Сегодня мне впервые потребовалось использовать их совместно с динамическим SQL.
12 августа 2020
INSERT в таблицу без указания значений полей
Все знают, что в команде INSERT имена полей таблицы не являются обязательными параметрами. Сразу скажу, что я никогда не использую подобный INSERT только с указанием значений полей, и вам не рекомендую. А вы задумывались, что список значений полей может тоже не являться обязательной частью этой команды?
15 октября 2019
Получение в программе значения первичного ключа после INSERT
Часто бывает, что после добавления строки в таблицу необходимо получить сгенерированное в СУБД значение первичного ключа. Например, это необходимо для последующей вставки detail-данных. Самый "оригинальный" способ, что я видел: стартуем транзакцию, вызываем INSERT, делаем запрос "select MAX(ID) from table", вставляем detail-данные, коммитим... Но мы пойдем другим путем – без дополнительных запросов к базе данных. Мы воспользуемся вызовом оператора INSERT с модификатором RETURNING. Вопрос только в том, как получить в программе значение из RETURNING?
13 февраля 2011
Сохранение в базу данных отчета FastReport в формате PDF
Недавно пришлось писать DLL, одна из функций которой должна была:
Для начала я создал процедуру, которая будет вставлять файл в базу данных и возвращать идентификатор вставленного файла.
1. сформировать отчет в FastReport;Предположим, что исходная структура таблицы для хранения файла в базе данных была такая (MS SQLServer 2000):
2. экспортировать отчет в файл PDF-формата и сохранить его в базе данных;
3. возвратить идентификатор сохраненного в базе данных файла.
CREATE TABLE X.FILES (где FILE_BODY – это поле, в которое сохраняется файл, а ID – идентификатор файла.
ID BIGINT IDENTITY NOT NULL,
FILE_BODY IMAGE NULL,
CONSTRAINT PK_FILES PRIMARY KEY (ID)),
Для начала я создал процедуру, которая будет вставлять файл в базу данных и возвращать идентификатор вставленного файла.
CREATE PROCEDURE X.InsertFile
@FILE image,
@ID bigint OUTPUT
AS
INSERT INTO X.FILES(FILE_BODY) VALUES(@FILE)
SET @ID = SCOPE_IDENTITY()
GO
Потом сел писать код DLL. В Delphi вся работа с файлами реализована с помощью потоков, поэтому я немного удивился, когда оказалось, что метод Export у TfrxReport экспортирует отчет только в файл (честно сказать, я ожидал увидеть, что-то в стиле ExportToStream). Т.е. вместо прямой передачи отчета через поток в базу данных, необходимо было сначала сохранить отчет во временный файл, а потом этот файл загрузить в базу данных. Мне это не понравилось, т.к. файловые операции (сначала записи, потом чтения) должны были хоть немного, но тормозить работу. Но нужно было срочно отдать DLL, поэтому я не стал разбираться с экспортом и сделал через файл:
...
db: TSDDatabase; // база данных SQLDirect
spInsertFile: TSDStoredProc; // вызов X.InsertFile
frxReport: TfrxReport;
frxPDFExport: TfrxPDFExport;
...
Function GetDoc(const sDotName: String; ...): Integer;
begin
Result := -1;
// загружаем шаблон отчета
If frxReport.LoadFromFile(sDotName)
then begin
// устанавливаем параметры отчета
...
If frxReport.PrepareReport
then try
// получаем имя временного файла
frxPDFExport.FileName := GetTempFileName;
Try
// экспортируем отчет во временный файл
frxReport.Export(frxPDFExport);
// загружаем PDF-файл в параметр процедуры
// из временного файла
spInsertFile.Params[1].LoadFromFile(frxPDFExport.FileName, ftBlob);
Except
on E: Exception do
WriteErrorMessage(E.Message);
End;
// сохраняем PDF-файл в базу данных
Try
db.StartTransaction;
spInsertFile.ExecProc;
db.Commit;
Result := spInsertFile.Params[2].AsInteger;
Except
on E: ESDEngineError do
begin
db.Rollback;
WriteErrorMessage(E.Message);
end;
End;
Finally
// удаляем временный файл
DeleteFile(frxPDFExport.FileName)
End
else WriteErrorMessage('Ошибка подготовки отчета')
end
else WriteErrorMessage('Файл шаблона не найден')
end;
После передачи DLL другому программисту, мысли о лишних файловых операциях при сохранении отчета в базу через временный файл, не давала мне покоя. Вечером, не найдя решения в документации по FastReport, я, прежде чем смотреть исходный код экспорта, решил еще раз пройтись по методам и свойствам экспорта. Глаз сразу же зацепился за свойство Stream. Я создал для этого свойства поток и метод Export у TfrxReport выгрузил отчет не в файл, а в поток.
Function GetDoc(const sDotName: String; ...): Integer;
begin
Result := -1;
// загружаем шаблон отчета
If frxReport.LoadFromFile(sDotName)
then begin
// устанавливаем параметры отчета
...
If frxReport.PrepareReport
then begin
Try
Try
// создаём поток в памяти
frxPDFExport.Stream := TMemoryStream.Create;
// экспортируем отчет в поток
frxReport.Export(frxPDFExport);
// загружаем PDF-файл в параметр процедуры
// из потока в памяти
spInsertFile.Params[1].LoadFromStream(frxPDFExport.Stream, ftBlob);
Except
on E: Exception do
WriteErrorMessage(E.Message);
End;
Finally
frxPDFExport.Stream.Free;
End;
// сохраняем PDF-файл в базу данных
Try
db.StartTransaction;
spInsertFile.ExecProc;
db.Commit;
Result := spInsertFile.Params[2].AsInteger;
Except
on E: ESDEngineError do
begin
db.Rollback;
WriteErrorMessage(E.Message);
end;
End;
end
else WriteErrorMessage('Ошибка подготовки отчета')
end
else WriteErrorMessage('Файл шаблона не найден')
end;
Часто решение задачи лежит на поверхности и нет нужды копаться в чужом коде. Нужно лишь быть внимательным и никогда не сдавайтесь – "ищите и обрящите".
Подписаться на:
Сообщения (Atom)

