Как загрузить файлы в соответствии с созданной датой в командной оболочке Windows через SQL Server xp_cmdshell

В SQL Server я использую следующий запрос для загрузки всех имен файлов ".jpg" из определенного каталога (например, z:) в таблицу.

Я хочу знать, есть ли способ загрузить файлы в соответствии с Дата создания вместо Измененная дата в командной строке Windows. Следующий запрос работает только с измененной датой при выполнении xp_cmdshell.

-- Create the table to store file list
CREATE TABLE myFilesTable (myFileID INT IDENTITY, myFileName NVARCHAR(256))

-- Insert file list from directory to SQL Server
DECLARE @Command varchar(1024) = 'z: & forfiles /m *.jpg /s /d 07/16/2015 /c "cmd /c echo @fdate @ftime @path"'

INSERT INTO myFilesTable
   EXEC MASTER.dbo.xp_cmdshell @Command

-- Check the list
SELECT * FROM myFilesTable
GO

07/16/2015 в переменной @Command находится Дата модификации. Очевидно, что команда forfiles не имеет понятия фильтровать файлы по Дата создания.

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

myFileID | myFileName
----------------------
1        | NULL
2        | 8/18/2015 11:13:08 AM "Z:\LDB1 App Export\Top Star_Aluminium Frames & Furniture (B)-31267.jpg"
3        | 8/19/2015 5:44:41 PM "Z:\LDB2 App Export\Soe Tint_Hardware Merchants & Ironmongers-31435.jpg"
4        | 8/19/2015 10:37:13 AM "Z:\Cover App Export\Taw Win Tun_Electrical Goods Sales & Repairing (A) -31382.jpg"
5        | 8/24/2015 10:34:33 AM "Z:\CP1 App Export\Thiri May_Fabric Shop (B)-30646.jpg"
6        | 8/17/2015 10:08:39 AM "Z:\CP2 App Export\Ko Tin Aung_Building Materials (B)-31300.jpg"

Я также попытался использовать команду dir с полем времени /t:c (время создания), что-то вроде

EXEC MASTER.dbo.xp_cmdshell 'dir z: *.jpg /t:c /s'

Он дает мне Дата создания, но показывает мне следующий результат, который не так ожидался. Я хочу, чтобы имена файлов были полными именами путей/каталогов, как показано в предыдущем результате.

myFileID | myFileName
----------------------
1        |  Volume in drive Z is Publication
2        |  Volume Serial Number is 3EF0-5CE4
3        | NULL
4        |  Directory of Z:\
5        | NULL
6        | 07/28/2015  06:41 PM    <DIR>          .
7        | 07/28/2015  07:06 PM    <DIR>          ..
8        | 03/05/2015  11:42 AM    <DIR>          LDB1 App Export
9        | 03/05/2015  05:31 PM    <DIR>          LDB2 App Export
10       |         0 File(s)              0 bytes
11       | NULL
12       |  Directory of Z:\LDB1 App Export
13       | NULL
14       | 03/05/2015  11:42 AM    <DIR>          .
15       | 07/28/2015  06:41 PM    <DIR>          ..
16       | 07/28/2015  06:49 PM         2,981,526 Kyaw Phay_Dental Equipment (A)-30998.jpg
17       | 08/31/2015  03:10 PM         3,126,629 Venus_Fashion Shops-31438.jpg
18       | 07/28/2015  06:49 PM         3,544,247 Marvellous_Tourism Services-30986.jpg
...      | ...

Ожидаемый результат должен выглядеть примерно так:

myFileID | CreatedDate           | myFileName
----------------------------------------------
1        | 8/10/2015 11:24:16 AM | "Z:\LDB1 App Export\Top Star_Aluminium Frames & Furniture (B)-31267.jpg"
2        | 8/10/2015 11:24:27 AM | "Z:\LDB2 App Export\Soe Tint_Hardware Merchants & Ironmongers-31435.jpg"
3        | 8/12/2015 10:05:22 AM | "Z:\Cover App Export\Taw Win Tun_Electrical Goods Sales & Repairing (A) -31382.jpg"
4        | 8/12/2015 10:05:22 AM | "Z:\CP1 App Export\Thiri May_Fabric Shop (B)-30646.jpg"
5        | 8/12/2015 10:05:22 AM | "Z:\CP2 App Export\Ko Tin Aung_Building Materials (B)-31300.jpg"

Любая помощь будет очень оценена:)

Ответ 1

Вот один из способов разобрать вывод команды DIR:

--Create the table to store file list
CREATE TABLE myFilesTable (myFileID INT IDENTITY, myFileCreateDate datetime, myFileName NVARCHAR(256))

--Create temporary table to store output of DIR command
CREATE TABLE #DirectoryOutput (LineID INT IDENTITY, LineData NVARCHAR(256))

--Insert file list from directory to SQL Server
DECLARE @Command varchar(1024) = 'dir z: *.jpg /t:c /s'

INSERT INTO #DirectoryOutput
   EXEC MASTER.dbo.xp_cmdshell @Command

--Check the list
insert into myFilesTable
select 
    convert(Datetime,(left(LineData, 20))) CreateDate,
    FilePath2.FilePath + '\' + right(LineData,len(LineData)-39) Filename
from #DirectoryOutput
cross apply
    (
    select Max(LineID) LineID
    from #DirectoryOutput FilePaths
    where LEFT(LineData,14)=' Directory of '
        and FilePaths.LineID < #DirectoryOutput.LineID
    ) FilePath1
join
    (
    select LineID, RIGHT(LineData, LEN(LineData)-14) FilePath
    from #DirectoryOutput FilePaths
    where LEFT(LineData,14)=' Directory of '
    ) FilePath2
on FilePath1.LineID = FilePath2.LineID
where ISDATE(left(LineData, 20))=1
order by 1

select * from myFilesTable

GO

Ответ 2

Я немного изменил вашу таблицу, чтобы добавить отдельный столбец для даты создания:

CREATE TABLE myFilesTable ( myFileID           int IDENTITY
                          , myFileName         nvarchar(256)
                          , myFileCreationDate datetime
                          )

Вы можете использовать следующий PowerShell script, чтобы получить информацию о каталоге и записать его в таблицу SQL:

Import-Module "C:\Program Files (x86)\Microsoft SQL Server\110\Tools\PowerShell\Modules\SQLPS" -DisableNameChecking
$files = Get-ChildItem "z:\" -Filter "*.jpg" -recurse | Where-Object { $_.CreationTime -ge "07/16/2015" } | Select-Object FullName, CreationTime
foreach ($file in $files) 
{
    $creationTime = $file.CreationTime -f "dd-MM-yyyy hh:mm:ss"
    $file.FullName = $file.FullName -replace "'", "''"
    Invoke-Sqlcmd -ServerInstance "YourInstance" `
              -Database "YourDatabase" `
              -Query ("INSERT INTO {0} (myFileName, myFileCreationDate) VALUES ('{1}', '{2}')" `
                            -f "myFilesTable", $file.FullName, $creationTime)
}

Замените значение YourInstance своим именем экземпляра и значением YourDatabase именем вашей базы данных.

Я настоятельно рекомендую использовать xp_cmdshell при открытии командной оболочки Windows с тем же контекстом безопасности, что и учетная запись службы SQL Server. Это риск безопасности, и лучше всего отключить команду xp_cmdshell.

Лучше всего выполнить команду PowerShell на SQL Server. Предпосылкой является наличие модуля SQLPS (для командлета Invoke-SqlCmd). Это предварительное условие выполняется, когда вы установили SQL Server.

EDIT:

Итак, если вы действительно хотите сделать это через xp_cmdshell, вы можете сохранить PowerShell script на своем SQL Server и выполнить его следующим образом (я изменил путь к файлу SQLPS в PowerShell script, предполагая, что вы имеют SQL Server 2012):

EXEC xp_cmdshell 'powershell.exe -file "C:\FileList.ps1" -ExecutionPolicy Unrestricted'

Где C:\FileList.ps1 - ваш сохраненный PowerShell script.

Ответ 3

forfiles предлагает только модифицированный фильтр даты (см. документы). Вместо этого вы можете выполнить PowerShell из SQL (например, как это), и поскольку у PowerShell много хороших фильтров, это будет легко сделать на основе созданной даты (например, как это).

Ответ 4

Если вы измените @Command на

DECLARE @Command varchar(1024) = '@echo off 
For /f "tokens=1-6 delims= " %%a in (''dir *.png /t:c /o:d'') do ( if exist %%e ( echo %%a %CD%%%e ))'

@echo off гарантирует, что команды не отображаются, и эта строка должна находиться на отдельной строке. Я избежал одиночных кавычек в SQL, заменив "на" (2 одинарные кавычки, а не двойную кавычку).

Команда dos производит следующий вывод:

Date       FileNameWithPath
07/15/2015 [Drive]:\[Path]\image.jpg

Надеюсь, это поможет вам приблизиться к тому, что вам нужно.