Экспорт результатов запроса в файл на лету - PullRequest
4 голосов
/ 22 апреля 2010

Мне нужно экспортировать результаты запроса в файл CSV и поместить файл в общую сетевую папку.

  1. Возможно ли достичь этого в рамках хранимой процедуры?
  2. Если да, приходит еще одно ограничение: могу ли я достичь этого без привилегий sysadmin, иначе без использования утилиты xp_cmdshell + BCP?
  3. Если «нет» 2. Должен ли вызывающий иметь привилегии sysadmin или будет достаточно, если у владельца SP есть привилегии sysadmin?

Вот некоторые подробности этой проблемы: SP должен экспортировать и передавать файл на лету и выдавать ошибку, если что-то пошло не так. Вызывающий должен немедленно получить ответ, т. Е. В случае отсутствия ошибки он может предположить, что результаты успешно переданы в папку. Поэтому задание DTS / SSIS, которое выполняется каждые N минут, не является вариантом. Я знаю, что проблема пахнет так, как будто мне придется делать это на уровне приложения, но я был бы более чем счастлив, если бы все эти вещи могли быть сделаны из T-SQL.

Ответы [ 4 ]

2 голосов
/ 01 мая 2010

Мне кажется, что вы не ждете SQL-кода в ответе на ваш вопрос. Основным аспектом вашего вопроса является аспект безопасности. Что вы должны сделать для реализации вашего требования без привилегий sysadmin и без новой дыры в безопасности? Это твой настоящий вопрос, я думаю.

Я вижу как минимум 3 способа решить вашу проблему. Но прежде всего короткое объяснение, почему привилегии sysadmin существуют во всех решениях, основанных на расширенных хранимых процедурах . Расширенные хранимые процедуры, такие как xp_cmdshell, очень старые. Они существовали, по крайней мере, до SQL Server 4.2, первого Microsoft SQL Server, работающего под первой Windows NT (NT 3.1). В старой версии SQL Server я не был ограничением безопасности для выполнения таких процедур, но позже один из них сделал такие ограничения. Важно понимать, что все процедуры общего назначения , которые позволяют запускать любой процесс под учетной записью SQL Server, например xp_cmdshell и sp_OACreate , должны иметь sysadmin ограничение привилегий. Только ориентированные на задачи процедуры с четкой областью использования и разрешениями на основе ролей могут решить проблему без дыры в безопасности. Итак, это 3 способа решения, которые я обещал ранее:

  • Вы создаете новую учетную запись SQL на своем сервере SQL с привилегиями sysadmin . Затем вы создаете хранимую процедуру, которая использует некоторые из расширенных хранимых процедур , например xp_cmdshell или sp_OACreate, и технически реализуете ваши требования (экспортируйте некоторую информацию в файл CSV). В отношении EXECUTE AS (см. http://msdn.microsoft.com/en-us/library/ms188354.aspx) вы настраиваете созданную хранимую процедуру так, чтобы она работала под учетной записью с привилегиями sysadmin . Вы делегируете выполнение этого Процедура для пользователей с некоторой ролью SQL, чтобы быть более гибкой со стороны делегирования разрешения.
  • Вы можете использовать CLR Хранимые процедуры вместо xp_cmdshell и sp_OACreate. Вы также должны использовать разрешения на основе ролей для созданной процедуры.
  • Конечный пользователь не вызывает напрямую хранимую процедуру SQL, которую вы создаете. Существует часть программного обеспечения (например, служба WCF или веб-сайт), которая вызывает вашу хранимую процедуру SQL. Вы можете реализовать экспорт в файл CSV внутри этого программного обеспечения, а не внутри какой-либо хранимой процедуры SQL.

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

1 голос
/ 26 апреля 2010

Можете ли вы использовать OLE Automation? Это уродливо, и вы, возможно, могли бы использовать некоторые методы построения строк на основе множества вместо курсора, но здесь идет ...

    Declare @Dir varchar(4000)
    Set @Dir = 'c:\some\path\accessible\to\SQLServer'

    If @Dir IS NULL
       Begin
        print 'dir is null.'
        Return 1
       End

    declare
        @FilePath as varchar(255),
        @DataToWrite as varchar(8000)

    If right(@DataDir,1) <> '\'
       Set @DataDir = @DataDir + '\'

    Set @FilePath = @DataDir + 'filename.csv' 

    DECLARE @RetCode int , @FileSystem int , @FileHandle int

    EXECUTE @RetCode = sp_OACreate 'Scripting.FileSystemObject' , @FileSystem OUTPUT
    IF (@@ERROR|@RetCode > 0 Or @FileSystem < 0)
    begin
      RAISERROR ('could not create FileSystemObject',16,1)

    End

    declare @FileExists int

    Execute @RetCode = sp_OAMethod @FileSystem, 'FileExists', @FileExists OUTPUT, @FilePath
    --print '@FileExists = ' + cast(@FileExists as varchar)

    If @FileExists = 1
    Begin
        RAISERROR ('file does not exist',16,1)
        /*return 1*/
    End

    --1 = for reading, 2 = for writing (will overwrite contents), 8 = for appending
    EXECUTE @RetCode = sp_OAMethod @FileSystem , 'OpenTextFile' , @FileHandle OUTPUT , @FilePath, 8, 1
    IF (@@ERROR|@RetCode > 0 Or @FileHandle < 0)
    begin
        RAISERROR ('could not create open text file',16,1)
    End


    DECLARE CSV CURSOR
    READ_ONLY
    FOR 

    Select Anything From MyDataTable
    order by whatever

    DECLARE @fld1 nvarchar(50)
        ,@fld2 nvarchar(50)

    OPEN CSV

    FETCH NEXT FROM CSV INTO @fld1, @fld2 

    WHILE (@@fetch_status <> -1)
    BEGIN
        IF (@@fetch_status <> -2)
        BEGIN

            Set @DataToWrite = @fld1 + ',' + @fld2 + char(13) + char(10) 
            EXECUTE @RetCode = sp_OAMethod @FileHandle , 'Write' , NULL , @DataToWrite 

            IF (@@ERROR|@RetCode > 0)
               begin
                RAISERROR ('could not write to file',16,1)

               End
        END

        FETCH NEXT FROM OpenOrders INTO @fld1, @fld2 

    END


CLOSE CSV
DEALLOCATE CSV

EXECUTE @RetCode = sp_OAMethod @FileHandle , 'Close' , NULL
IF (@@ERROR|@RetCode > 0)
RAISERROR ('Could not close file',16,1)

EXEC sp_OADestroy @FileSystem

return 0

End
1 голос
/ 28 апреля 2010

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

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

  • xp_cmdshell - инструмент выбора для манипулирования файлами.
  • Мне нравится решение sp_OA *, потому что оно дает мне воспоминания о SQL 7.0. Но использование этих функций всегда заставляло меня нервничать.
  • Возможно, вы сможете что-то сделать с OPENROWSET, где целью вставки является файл, определенный с помощью этой функции. Звучит маловероятно, возможно, стоит посмотреть.
  • Аналогичным образом, определение связанного сервера может использоваться в качестве цели для вставок или выбора ... в ... операторах.

Похоже, безопасность - это ваш показ. По большому счету, когда SQL отправляется в ОС, он обладает всеми правами учетной записи NT, под которой запускается служба SQL; если вы хотите ограничить доступ к сети, тщательно настройте эту учетную запись (и никогда не назначайте ее администратором домена!)

Можно вызвать xp_cmdshell от имени пользователя без прав sysadmin и настроить эти вызовы так, чтобы они не имели тех же прав доступа, что и учетная запись SQL Service NT. Согласно BOL (SQL 2005 и выше):


xp_cmdshell Proxy Account
Когда он вызывается пользователем, который не является членом предопределенной роли сервера sysadmin, xp_cmdshell подключается к Windows, используя имя учетной записи и пароль, хранящиеся в учетных данных с именем ## xp_cmdshell_proxy_account ##. Если эти учетные данные прокси не существуют, xp_cmdshell завершится ошибкой.

Учетные данные прокси-сервера можно создать, выполнив процедуру sp_xp_cmdshell_proxy_account. В качестве аргументов эта хранимая процедура принимает имя пользователя и пароль Windows. Например, следующая команда создает учетные данные прокси для пользователя домена Windows SHIPPING \ KobeR с паролем Windows sdfh% dkc93vcMt0.


Таким образом, ваш пользователь входит в систему с любыми правами пользователя ( не sysadmin!) И выполняет хранимую процедуру, которая вызывает xp_cmdshell, которая «подхватит» все настроенные права прокси. Опять же, неловко, но звучит так, как будто бы ты сделал то, что хотел. (Возможным ограничивающим фактором является то, что вы получаете только одну учетную запись прокси, поэтому она должна соответствовать всем возможным потребностям.)

Честно говоря, мне кажется, что лучшим решением было бы:

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

Итак, что запускает вызов хранимой процедуры?

1 голос
/ 22 апреля 2010

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

В общем, это довольно необычное требование - чего вы пытаетесь выполнить?

UPDATE: После некоторых размышлений - это проблема проектирования, и я не смог найти решение, просто используя SQL Server SP.

В прошлом - вот что я сделал:

  • на уровне приложения - реализовать асинхронный процесс, при котором пользователь нажимает кнопку, запрашивая загрузку файла; приложение принимает и отпускает пользователя
  • пользователь может проверить статус через страницу статуса или получит электронное письмо, когда это будет сделано или произошла ошибка
  • в то же время прикладной уровень, пики пакета SSIS или задания агента SQL
  • Если нужны параметры - используйте дизайн и внедрите специальную таблицу: JOB_PARAMETERS - где вы бы поместили параметры
  • вам также потребуется создать больше таблиц для управления заданиями, сохранения статуса задания и связи с прикладным уровнем
  • вы можете захотеть использовать SQL Server Broker на уровне БД
  • Возможно, вы захотите использовать MSMQ на уровне приложения

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...