如何根据 Windows 命令 shell 中的创建日期通过 SQL 服务器的 xp_cmdshell 加载文件
How to load files according to Created Date in Windows command shell via SQL Server's xp_cmdshell
在 SQL 服务器中,我使用下面的查询将特定目录(例如 z:) 中的所有“.jpg”文件名加载到 table 中。
我想知道是否有办法根据创建日期而不是Windows中的修改日期加载文件命令提示符。下面的查询仅在执行 xp_cmdshell
.
时适用于 Modified Date
-- 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
变量@Command
中的07/16/2015
是修改日期。显然命令 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'
它给了我 创建日期 但它显示了以下与预期不同的结果。我想要完整 path/directory 名称的文件名,如上一个结果所示。
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"
任何帮助将不胜感激:)
forfiles
仅提供修改日期过滤器 (see docs). Instead you can execute PowerShell from within SQL (e.g. like this) and since PowerShell has lots of nice filters it'll be easy to do that based on Created Date (e.g. like this)。
这是一种解析 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
我稍微更改了您的 table 以包含创建日期的单独列:
CREATE TABLE myFilesTable ( myFileID int IDENTITY
, myFileName nvarchar(256)
, myFileCreationDate datetime
)
您可以使用以下 PowerShell 脚本获取目录信息并将其写入 SQL table:
Import-Module "C:\Program Files (x86)\Microsoft SQL Server0\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 命令 shell,其安全上下文与 SQL 服务器服务帐户相同。这是一个安全风险,最好禁用 xp_cmdshell 命令。
您最好在 SQL 服务器上执行 PowerShell 命令。先决条件是 SQLPS 模块可用(用于 Invoke-SqlCmd commandlet)。当您安装 SQL 服务器时满足此先决条件。
编辑:
因此,如果您真的想通过 xp_cmdshell 执行此操作,您可以将 PowerShell 脚本保存在 SQL 服务器上并按以下方式执行(我将路径修改为 SQLPowerShell 脚本中的 PS 文件,假设您有 SQL Server 2012):
EXEC xp_cmdshell 'powershell.exe -file "C:\FileList.ps1" -ExecutionPolicy Unrestricted'
其中 C:\FileList.ps1 是您保存的 PowerShell 脚本。
如果您将@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 确保不显示命令并且此行必须在单独的行上。
我通过将 ' 替换为 ''(2 个单引号而不是双引号)来转义 SQL 中的单引号。
dos 命令产生以下输出:
Date FileNameWithPath
07/15/2015 [Drive]:\[Path]\image.jpg
我希望这可以帮助您更接近您的需求。
在 SQL 服务器中,我使用下面的查询将特定目录(例如 z:) 中的所有“.jpg”文件名加载到 table 中。
我想知道是否有办法根据创建日期而不是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
变量@Command
中的07/16/2015
是修改日期。显然命令 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'
它给了我 创建日期 但它显示了以下与预期不同的结果。我想要完整 path/directory 名称的文件名,如上一个结果所示。
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"
任何帮助将不胜感激:)
forfiles
仅提供修改日期过滤器 (see docs). Instead you can execute PowerShell from within SQL (e.g. like this) and since PowerShell has lots of nice filters it'll be easy to do that based on Created Date (e.g. like this)。
这是一种解析 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
我稍微更改了您的 table 以包含创建日期的单独列:
CREATE TABLE myFilesTable ( myFileID int IDENTITY
, myFileName nvarchar(256)
, myFileCreationDate datetime
)
您可以使用以下 PowerShell 脚本获取目录信息并将其写入 SQL table:
Import-Module "C:\Program Files (x86)\Microsoft SQL Server0\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 命令 shell,其安全上下文与 SQL 服务器服务帐户相同。这是一个安全风险,最好禁用 xp_cmdshell 命令。
您最好在 SQL 服务器上执行 PowerShell 命令。先决条件是 SQLPS 模块可用(用于 Invoke-SqlCmd commandlet)。当您安装 SQL 服务器时满足此先决条件。
编辑:
因此,如果您真的想通过 xp_cmdshell 执行此操作,您可以将 PowerShell 脚本保存在 SQL 服务器上并按以下方式执行(我将路径修改为 SQLPowerShell 脚本中的 PS 文件,假设您有 SQL Server 2012):
EXEC xp_cmdshell 'powershell.exe -file "C:\FileList.ps1" -ExecutionPolicy Unrestricted'
其中 C:\FileList.ps1 是您保存的 PowerShell 脚本。
如果您将@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 确保不显示命令并且此行必须在单独的行上。 我通过将 ' 替换为 ''(2 个单引号而不是双引号)来转义 SQL 中的单引号。
dos 命令产生以下输出:
Date FileNameWithPath
07/15/2015 [Drive]:\[Path]\image.jpg
我希望这可以帮助您更接近您的需求。