#sql-server #delphi #ado
#sql-сервер #delphi #ado
Вопрос:
Я хочу сделать следующее. 1) Создайте базу данных. 2) Запускайте скрипт при создании таблиц, хранимых процедур и т.д. (этот скрипт создается с помощью опции SMS «генерировать скрипты»)
Я нашел следующий код:http://www.delphipages.com/forum/showthread.php?t=181685 и изменил его на этот:
попробуйте
ADOQuery.ConnectionString := 'Provider=SQLOLEDB.1;Password='
edtPassword.Текст
‘; Сохраняемая информация о безопасности = True; Идентификатор пользователя = ‘ edtUser.Text
‘;Начальный каталог = master; Источник данных =’
Имя_сервера.Текст;ADOQuery.SQL.Clear; ADOQuery.SQL.Text := 'create DataBase ' edtWebDBName.Text; ADOQuery.ExecSQL; // should check existance of database ADOWeb.Connected := false; ADOWeb.ConnectionString := 'Provider=SQLOLEDB.1;Password='
edtPassword.Текст
‘; Сохраняемая информация о безопасности = True; Идентификатор пользователя = ‘ edtUser.Text
‘;Начальный каталог=’ edtWebDBName.Текст ‘;Источник данных =’
Имя_сервера.Текст;
ADOWeb.Подключено:= true;ADOQuery.Connection := ADOWeb; ADOQuery.SQL.Clear; ADOQuery.SQL.LoadFromFile(edtScriptFileName.Text); ADOQuery.ExecSQL; except
Это работает до момента запуска файла сценария. Затем он генерирует исключение: неправильный синтаксис рядом с «GO». Если я запускаю скрипт в SMS на вновь созданной базе данных, все в порядке. Связана ли эта проблема с одновременным выполнением более чем одной команды SQL (сценарий, по сути, представляет собой длинный список инструкций command / GO? Как это обойти?
О, также в качестве бонуса, есть какие-нибудь мысли о быстрой проверке, чтобы увидеть, действительно ли новая база данных существует, прежде чем отправлять в нее скрипт? (Или это не обязательно, поскольку при сбое create это сгенерирует исключение?)
Комментарии:
1. Все эти ответы будут работать. Я думаю, что для сценариев, генерируемых SMS, запуск sqlcmd — это правильный путь. Также я использовал приведенное ниже, чтобы получить количество БД. ADOQuery.SQL.Text := ‘ВЫБЕРИТЕ COUNT(*) ИЗ sys.databases, ГДЕ name=’ chr(39) edtWebDBName. Текст chr(39); ADOQuery. Открыть; если ADOQuery. Поля[0]. AsInteger = 0, тогда // DB НЕ СУЩЕСТВУЕТ
Ответ №1:
Оператор Rob GO
не распознается ADO, поэтому вы должны удалить его из своего скрипта перед выполнением.
Теперь, чтобы проверить, существует ли база данных, вы можете выполнить запрос, подобный этому
select COUNT(*) from sys.databases where name='yourdatabasename'
проверьте этот очень простой пример
предположим, что у вас есть скрипт, подобный этому
CREATE TABLE Dummy.[dbo].tblUsers(ID INT, UserName VARCHAR(50))
GO
INSERT INTO Dummy.[dbo].tblUsers (ID, UserName) VALUES (1, 'Jill')
GO
INSERT INTO Dummy.[dbo].tblUsers (ID, UserName) VALUES (2, 'John')
GO
INSERT INTO Dummy.[dbo].tblUsers (ID, UserName) VALUES (3, 'Jack')
GO
Теперь, чтобы выполнить это предложение, вы можете сделать что-то вроде этого
const
//in this case the script is inside of a const string but can be loaded from a file as well
Script=
'CREATE TABLE Dummy.[dbo].tblUsers(ID INT, UserName VARCHAR(50)) ' #13#10
'GO ' #13#10
'INSERT INTO Dummy.[dbo].tblUsers (ID, UserName) VALUES (1, ''Jill'') ' #13#10
'GO ' #13#10
'INSERT INTO Dummy.[dbo].tblUsers (ID, UserName) VALUES (2, ''John'') ' #13#10
'GO ' #13#10
'INSERT INTO Dummy.[dbo].tblUsers (ID, UserName) VALUES (3, ''Jack'') ' #13#10
'GO ';
var
DatabaseExist : Boolean;
i : Integer;
begin
try
//check the connection
if not ADOConnection1.Connected then
ADOConnection1.Connected:=True;
//make the query to check if the database called Dummy exist
ADOQuery1.SQL.Add(Format('select COUNT(*) from sys.databases where name=%s',[QuotedStr('Dummy')]));
ADOQuery1.Open;
try
//get the returned value, if is greater than 0 then exist
DatabaseExist:=ADOQuery1.Fields[0].AsInteger>0;
finally
ADOQuery1.Close;
end;
if not DatabaseExist then
begin
//create the database if not exist
ADOQuery1.SQL.Text:=Format('Create Database %s',['Dummy']);
ADOQuery1.ExecSQL;
ADOQuery1.Close;
//load the script, remember can be load from a file too
ADOQuery1.SQL.Text:=Script;
//parse the script to remove the GO statements
for i := ADOQuery1.SQL.Count-1 downto 0 do
if StartsText('GO',ADOQuery1.SQL[i]) then
ADOQuery1.SQL.Delete(i);
//execute the script
ADOQuery1.ExecSQL;
ADOQuery1.Close;
end;
except
on E:Exception do
ShowMessage(E.Message);
end;
end;
Комментарии:
1. Почему -1 здесь? Есть разумная причина для этого?
2. @daemon_x, не волнуйся ;), я так привык к анонимным отказникам, на меня это больше не влияет.
Ответ №2:
Это GO означает завершение пакета только для определенных утилит Microsoft, это неправильный оператор T-SQL. Попробуйте удалять каждое вхождение GO
в вашем скрипте, а затем выполнять его. Это GO
будет выполнено ADOQuery.ExecSQL
для вас в конце вашего скрипта.
И к вашему второму вопросу; вы можете использовать, например, SQL-функцию DB_ID, чтобы проверить, существует ли ваша база данных (вы, конечно, должны быть на том же сервере). Эта функция возвращает идентификатор базы данных; в противном случае NULL, поэтому, если следующая инструкция SQL возвращает NULL, то создание вашей базы данных завершилось неудачей.
ADOQuery.SQL.Text := 'SELECT DB_ID(' edtWebDBName.Text ')';
ADOQuery.Open;
if ADO_Query.Fields[0].IsNull then
ShowMessage('Database creation failed');
Ответ №3:
Скрипты могут содержать гораздо больше команд, чем SQL DDL / DML. Они могут содержать переменные, небольшие блоки кода, инструкцию по управлению транзакциями. Обычно существует более одного оператора, разделенных символом завершения (точка с запятой, косая черта Oracle, MSSQL GO и т.д., В зависимости от используемой вами базы данных и синтаксиса ее скрипта). Для правильного выполнения скрипта вы должны проанализировать входной файл, разделить каждую команду и правильно передать ее в базу данных. Вы можете поискать библиотеку для этого (есть несколько, IIRC), или вы можете попробовать использовать инструмент командной строки MS SQL для отправки скрипта через нее.