SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

SQL Server 2012新特性(1)T-SQL操作FileTable目录实例
          在SQL Server 2008提供FileStream,以借助Windows系统本身的API来强化SQL Server对于非结构化数据的支持后,SQL Server 2012更是推出了像Contained Database、FileTable等令人期待的新功能。对于FileTable的功能和特性,在此无需赘述,本文主要针对FileTable的T-SQL操作目录做一个实例演示。

关于FileTable的介绍,请参阅MSDN:\\\\%20\\机器名\SQL实例名\File%20Table数据库目录\File%20Talbe目录名%20%20此目录层次结构构成了%20FileTable%20的文件命名空间的根。%20在此目录层次结构下,FileTable%20的%20FILESTREAM%20数据作为文件存储,并且存储为也包含文件和子目录的子目录。%20%20请务必记住:在此实例级别%20FILESTREAM%20共享区(即本实例中的“NET2012”)下创建的目录层次结构是虚拟目录层次结构。%20该层次结构存储于%20SQL%20Server%20数据库中,并且在物理上不在%20NTFS%20文件系统中表示。%20访问%20FILESTREAM%20共享区之下和其包含的%20FileTable%20中的文件和目录的所有操作都将被文件系统中嵌入的%20SQL%20Server%20组件拦截和处理。%20%20select%20*%20from%20[dbo].MyFileTable01;%20%20注意:上图并没有目录结构,换句话说,都是位于根目录下的“平级”文件。如果要获取文件的完整路径,这需要结合使用%20FileTableRootPath%20(Transact-SQL)%20和%20GetFileNamespacePath%20(Transact-SQL)%20函数查看完整路径:%20USE%20LearnFileTable;%20DECLARE%20@root%20nvarchar(100);%20DECLARE%20@fullpath%20nvarchar(1000);%20%20SELECT%20@root%20=%20FileTableRootPath();%20SELECT%20@fullpath%20=%20@root%20+%20file_stream.GetFileNamespacePath()%20%20%20%20%20FROM%20[dbo].MyFileTable01%20%20%20%20%20WHERE%20name%20=%20N'DemoExcel.xlsx';%20%20PRINT%20@fullpath;%20GO%20%20除了手动创建目录、还可以通过T-SQL创建FileTable目录。%20四、通过T-SQL创建FileTable目录%20这个过程我们分三步:%20(1)创建一个新目录%20INSERT%20INTO%20dbo.MyFileTable01(name,%20is_directory)%20SELECT%20'MyDir01',%201;%20%20select%20stream_id,file_stream,name,path_locator,is_directory%20from%20[dbo].MyFileTable01;%20%20(2)插入一个空白文件到新目录:%20%20DECLARE%20@path%20%20%20%20%20%20%20%20HIERARCHYID%20DECLARE%20@new_path%20%20%20%20VARCHAR(675)%20%20SELECT%20@path%20=%20path_locator%20FROM%20dbo.MyFileTable01%20WHERE%20name%20=%20'MyDir01'%20%20SELECT%20@new_path%20=%20@path.ToString()%20%20%20%20%20+%20CONVERT(VARCHAR(20),%20CONVERT(BIGINT,%20SUBSTRING(CONVERT(BINARY(16),%20NEWID()),%201,%206)))%20+%20'.'%20+%20CONVERT(VARCHAR(20),%20CONVERT(BIGINT,%20SUBSTRING(CONVERT(BINARY(16),%20NEWID()),%207,%206)))%20+%20'.'%20+%20CONVERT(VARCHAR(20),%20CONVERT(BIGINT,%20SUBSTRING(CONVERT(BINARY(16),%20NEWID()),%2013,%204)))%20+%20'/'%20%20INSERT%20INTO%20dbo.MyFileTable01(name,%20file_stream,%20path_locator)%20SELECT%20N'空文件.txt',%200x,%20@new_path%20%20select%20stream_id,file_stream,name,path_locator,is_directory%20from%20[dbo].MyFileTable01;%20%20%20如果你不想使用newId(),而要使用SQL%20Server本身提供的hierarchyid层次结构,可以使用下面这个函数:%20%20CREATE%20FUNCTION%20[dbo].[fnGetNewPathLocator]%20%20%20%20%20%20(@child%20uniqueidentifier%20%20%20%20%20,@parent%20hierarchyid%20=%20NULL)%20RETURNS%20%20%20%20hierarchyid%20AS%20BEGIN%20%20%20%20%20DECLARE%20%20%20%20@result%20hierarchyid,%20%20%20%20%20%20%20%20%20@binId%20binary(16)%20=%20CONVERT(binary(16),%20@child);%20%20%20%20%20SELECT%20@result%20=%20hierarchyid::Parse%20%20%20%20%20%20%20%20%20(%20%20%20%20%20%20%20%20%20%20%20%20%20COALESCE(@parent.ToString(),%20N'/')%20+%20%20%20%20%20%20%20%20%20%20%20%20%20CONVERT(nvarchar,%20CONVERT(bigint,%20SUBSTRING(@binId,%201,%206)))%20+%20N'.'%20+%20%20%20%20%20%20%20%20%20%20%20%20%20CONVERT(nvarchar,%20CONVERT(bigint,%20SUBSTRING(@binId,%207,%206)))%20+%20N'.'%20+%20%20%20%20%20%20%20%20%20%20%20%20%20CONVERT(nvarchar,%20CONVERT(bigint,%20SUBSTRING(@binId,%2013,%204)))%20+%20N'/'%20%20%20%20%20%20%20%20%20);%20%20%20%20%20RETURN%20@result;%20END;%20%20我们使用该函数插入同样的一个图片文件到该目录下:%20%20DECLARE%20@image1%20%20%20%20VARBINARY(MAX)%20--DECLARE%20@stream_id%20%20%20%20%20%20%20%20HIERARCHYID%20DECLARE%20@path_locator%20%20%20%20%20%20%20HIERARCHYID%20DECLARE%20@new_path%20%20%20%20VARCHAR(675)%20%20SELECT%20@image1%20=%20CAST(bulkcolumn%20AS%20VARBINARY(MAX))%20FROM%20OPENROWSET(BULK%20N'E:\Test\悲剧.jpg',%20SINGLE_BLOB)%20AS%20x%20%20SELECT%20@path_locator=path_locator%20FROM%20dbo.MyFileTable01%20WHERE%20name%20=%20'MyDir01'%20%20%20INSERT%20INTO%20dbo.MyFileTable01(name,%20file_stream,%20path_locator)%20SELECT%20N'悲剧.jpg',%20@image1,%20[dbo].[fnGetNewPathLocator](NEWID(),@path_locator)%20as%20NewPath%20%20%20select%20stream_id,file_stream,name,path_locator,parent_path_locator,is_directory%20from%20[dbo].MyFileTable01;%20%20如果想更进一步,让FileTable目录显示更加接近文件系统,可以将系统stream_Id字段替换为年+月+加标识符等,可以看这里的示例:%20http:/www.codeproject.com/Articles/584865/SQL-Server-FileTable-My-first-experience%20%20%20%20注意事项:%201、%20FileTable目录中不能存储15个级别的子目录,并且存储15个级别的子目录时,最下面的一级不能包含文件,因为这些文件将代表另外一个附加的级别。%20%202、%20NTFS%20文件系统支持远远超过Windows外壳程序和大多数Windows%20API的260个字符限制的路径名。因此,使用Transact-SQL在%20FileTable的文件层次结构中创建的文件有可能无法使用Windows资源管理器或很多其他Windows应用程序查看或打开,原因是这些文件的完整路径名称超过了260个字符。但是,您可使用%20Transact-SQL继续访问这些文件。%20%20%20关于SQL%20Server%202008中新增的原生分层结构数据hierarchyid,请看这里:%20http:/www.cnblogs.com/downmoon/archive/2011/05/03/2035259.html%20http:/msdn.microsoft.com/zh-cn/library/bb677173%28v=sql.100%29.aspx%20http:/msdn.microsoft.com/zh-cn/library/bb677173.aspx%20http:/msdn.microsoft.com/en-us/magazine/cc794278.aspx#id0090037%20%20本文参考文章:%20http:/www.codeproject.com/Articles/584865/SQL-Server-FileTable-My-first-experience%20http:/www.toadworld.com/platforms/sql-server/b/weblog/archive/2013/08/06/inserting-files-into-a-filetable-using-t-sql.aspx%20http:/www.cnblogs.com/zitjubiz/archive/2012/11/14/SQLSERVER_FileStream_FileTable.html">http://technet.microsoft.com/zh-cn/library/ff929144.aspx

一、启用FileTable的先决条件

http://technet.microsoft.com/zh-cn/library/gg509097.aspx

USE master GO
EXEC sp_configure 'filestream access level',2
Go
RECONFIGURE GO
--查看实例级FileTable配置
EXEC sp_configure filestream_access_level;
GO

二、创建一个FileTable

USE master
GO
IF EXISTS (SELECT name FROM sys.databases WHERE name = N'LearnFileTable')
         DROP DATABASE LearnFileTable
GO
/****** Object:  Database [LearnFileTable]    Script Date: 2014-04-23 9:25:32 ******/
CREATE DATABASE [LearnFileTable]
 CONTAINMENT = NONE
 ON  PRIMARY
( NAME = N'LearnFileTable_Primary', FILENAME = N'E:\SQL2012Data\MyData\2012Data\LearnFileTable_Data.mdf' ,
SIZE = 8128KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
 FILEGROUP [MyFS] CONTAINS FILESTREAM  DEFAULT
( NAME = N'LearnFileFS', FILENAME = N'E:\SQL2012Data\MyData\2012Data\LearnFileFS' ,
 MAXSIZE = UNLIMITED)
 LOG ON
( NAME = N'LearnFileTable_Log', FILENAME = N'E:\SQL2012Data\MyData\2012Data\LearnFileTable_Log.ldf' ,
SIZE = 8128KB , MAXSIZE = 2097152KB , FILEGROWTH = 10%)
WITH FILESTREAM (NON_TRANSACTED_ACCESS   = FULL, DIRECTORY_NAME = N'LearnFileTable')
GO

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

三、创建FileTable数据表

USE LearnFileTable
GO
CREATE TABLE MyFileTable01  AS FileTable
WITH
(
      FileTable_Directory =   'MyFileTable01',
      FileTable_Collate_Filename = database_default
);
GO

select * from [dbo].MyFileTable01;

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

注意,上图中的目录层次为:\\<machine>\<instance-level FILESTREAM share>\<database-level directory>\<FileTable directory>\
(\\机器名\SQL实例名\FileTable数据库目录\FileTable目录名)
 此目录层次结构构成了 FileTable 的文件命名空间的根。 在此目录层次结构下,FileTable 的 FILESTREAM 数据作为文件存储(包含文件和子目录的子目录)。

请务必记住:在此实例级别 FILESTREAM 共享区(即本实例中的“NET2012”)下创建的目录层次结构是虚拟目录层次结构。 该层次结构存储于 SQL Server 数据库中,并且在物理上不在NTFS文件系统中表示。 访问FILESTREAM 共享区之下和其包含的 FileTable 中的文件和目录的所有操作都将被文件系统中嵌入的 SQL Server 组件拦截和处理。

此时,我们可以手动添加几个文件到该FileTable目录下:

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

重新查询:

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

注意:上图并没有根目录之外的常见文件目录结构,换句话说,都是位于根目录下的“平级”文件。如果要获取文件的完整路径,这需要结合使用 FileTableRootPath (Transact-SQL) 和 GetFileNamespacePath (Transact-SQL) 函数查看完整路径:

USE LearnFileTable;
DECLARE @root nvarchar(100);
DECLARE @fullpath nvarchar(1000);

SELECT @root = FileTableRootPath();
SELECT @fullpath = @root + file_stream.GetFileNamespacePath()
    FROM [dbo].MyFileTable01
    WHERE name = N'DemoExcel.xlsx';

PRINT @fullpath;
GO

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例
  除了手动创建目录、还可以通过T-SQL创建FileTable目录。


四、通过T-SQL创建FileTable目录
这个过程我们分两步:
(1)创建一个新目录

INSERT INTO dbo.MyFileTable01(name, is_directory)
SELECT 'MyDir01', 1;
select stream_id,file_stream,name,path_locator,is_directory from [dbo].MyFileTable01;
SQL Server 2012新特性(一)T-SQL操作FileTable目录实例
(2)插入一个空白文件到新目录:

DECLARE @path        HIERARCHYID
DECLARE @new_path    VARCHAR(675)

SELECT @path = path_locator
FROM dbo.MyFileTable01
WHERE name = 'MyDir01'

SELECT @new_path = @path.ToString()     +
CONVERT(VARCHAR(20), CONVERT(BIGINT, SUBSTRING(CONVERT(BINARY(16), NEWID()), 1, 6))) + '.' +
CONVERT(VARCHAR(20), CONVERT(BIGINT, SUBSTRING(CONVERT(BINARY(16), NEWID()), 7, 6))) + '.' +
CONVERT(VARCHAR(20), CONVERT(BIGINT, SUBSTRING(CONVERT(BINARY(16), NEWID()), 13, 4))) + '/'

INSERT INTO dbo.MyFileTable01(name, file_stream, path_locator)
SELECT N'空文件.txt', 0x, @new_path

--select stream_id,file_stream,name,path_locator,is_directory from [dbo].MyFileTable01
SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

如果你想使用SQL Server本身提供的hierarchyid层次结构,下面这个函数也许可以帮你:

CREATE FUNCTION [dbo].[fnGetNewPathLocator]
    (@child uniqueidentifier
    ,@parent hierarchyid = NULL)
RETURNS    hierarchyid
AS
BEGIN
    DECLARE    @result hierarchyid,
        @binId binary(16) = CONVERT(binary(16), @child);
    SELECT @result = hierarchyid::Parse
        (
            COALESCE(@parent.ToString(), N'/') +
            CONVERT(nvarchar, CONVERT(bigint, SUBSTRING(@binId, 1, 6))) + N'.' +
            CONVERT(nvarchar, CONVERT(bigint, SUBSTRING(@binId, 7, 6))) + N'.' +
            CONVERT(nvarchar, CONVERT(bigint, SUBSTRING(@binId, 13, 4))) + N'/'
        );
    RETURN @result;
END;

我们使用该函数插入一个图片文件到该目录下:

DECLARE @image1    VARBINARY(MAX)
--DECLARE @stream_id        HIERARCHYID
DECLARE @path_locator       HIERARCHYID

SELECT @image1 = CAST(bulkcolumn AS VARBINARY(MAX))
FROM OPENROWSET(BULK N'E:\Test\悲剧.jpg', SINGLE_BLOB) AS x

SELECT @path_locator=path_locator FROM dbo.MyFileTable01 WHERE name = 'MyDir01'

INSERT INTO dbo.MyFileTable01(name, file_stream, path_locator)
SELECT N'悲剧.jpg', @image1, [dbo].[fnGetNewPathLocator](NEWID(),@path_locator) as NewPath

select stream_id,file_stream,name,path_locator,parent_path_locator,is_directory from [dbo].MyFileTable01;

注意上面两种方法中,一个path_locator为Varchar,一个为HIERARCHYID

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例

SQL Server 2012新特性(一)T-SQL操作FileTable目录实例
如果想更进一步,让FileTable目录显示更加接近文件系统,可以将系统stream_Id字段替换为年+月+加标识符等,可以看这里的示例:
http://www.codeproject.com/Articles/584865/SQL-Server-FileTable-My-first-experience


特别限制
1、 FileTable目录中不能存储15个级别的子目录,并且存储15个级别的子目录时,最下面的一级不能包含文件,因为这些文件将代表另外一个附加的级别。
2、 NTFS 文件系统支持远远超过Windows外壳程序和大多数Windows API的260个字符限制的路径名。因此,使用Transact-SQL在 FileTable的文件层次结构中创建的文件有可能无法使用Windows资源管理器或很多其他Windows应用程序查看或打开,原因是这些文件的完整路径名称超过了260个字符。但是,您可使用 Transact-SQL继续访问这些文件。

关于SQL Server 2008中新增的原生分层结构数据hierarchyid,请看这里:
http://www.cnblogs.com/downmoon/archive/2011/05/03/2035259.html
http://msdn.microsoft.com/zh-cn/library/bb677173.aspx


本文参考文章:
http://www.codeproject.com/Articles/584865/SQL-Server-FileTable-My-first-experience
http://www.toadworld.com/platforms/sql-server/b/weblog/archive/2013/08/06/inserting-files-into-a-filetable-using-t-sql.aspx
http://www.cnblogs.com/zitjubiz/archive/2012/11/14/SQLSERVER_FileStream_FileTable.html


邀月注:本文版权由邀月和****共同所有,转载请注明出处。
助人等于自助!   3w@live.cn