MSSQL的SSIS中获取FTP文件列表的方法

MSSQL 2005 的SSIS里提供的FTP包括以下功能:
Send files 上传文件
Receive files 接收文件
Create local directory 创建本地目录
Create remote directory 创建远程目录
Remove local directory 删除本地目录
Remove remote directory 删除远程目录
Delete local files 删除本地文件
Delete remote files 删除远程文件

没有可以用于列表、下载所有FTP服务器上文件的功能。

SSIS中的 Foreach Loop Container 功能只适用本地目录、文件,无法处理FTP服务器上的目录和文件。

我们可以通过 Script task 脚本功能来实现FTP远程文件处理。下面的SSIS脚本演示获取远程FTP的所有 Demo*.xls 文件,然后下载这些文件,并在FTP服务器上删除所有已下载的文件。

其中 SetWorkingDirectory 可以用于指定FTP上的工作目录。

    Public Sub Main()
        Dim result As Integer
        Dim conMan As ConnectionManager
        Dim ftp_client As FtpClientConnection
        Dim sFolderNames() As String
        Dim sFileNames() As String
        Dim sFileName(0) As String

        conMan = Dts.Connections("MyFTP")
        ftp_client = New FtpClientConnection(conMan.AcquireConnection(Nothing))

        ftp_client.Connect()
        ftp_client.SetWorkingDirectory("incoming")
        ftp_client.GetListing(sFolderNames, sFileNames)

        For Each fileName As String In sFileNames
            sFileName(0) = fileName
            If fileName.EndsWith("xls", StringComparison.OrdinalIgnoreCase) And fileName.StartsWith("Demo", StringComparison.OrdinalIgnoreCase) Then
                ftp_client.ReceiveFiles(sFileName, "D:\Test\ftp_data\", True, False)
                ftp_client.DeleteFiles(sFileName)
            End If
        Next fileName

        ftp_client.Close()

        Dts.TaskResult = Dts.Results.Success
    End Sub

现在所有需要的文件都传到本地目录,就可以使用 Foreach Loop Container 循环容器来处理了。

生成启用、禁止和删除外部关键字约束的SQL脚本

利用主关键字表来自动生成:启用、禁止和删除数据表中外部关键字约束的SQL脚本

源代码:

-- Enable, Disable, Drop and Recreate FKs based on Primary Key table  
-- Written 2007-11-18  
-- Edgewood Solutions / MSSQLTips.com  
-- Works for SQL Server 2005  

SET NOCOUNT ON  

DECLARE @operation VARCHAR(10)  
DECLARE @tableName sysname  
DECLARE @schemaName sysname  

SET @operation = 'DROP' --ENABLE, DISABLE, DROP  
SET @tableName = 'SpecialOfferProduct'  
SET @schemaName = 'Sales'  

DECLARE @cmd NVARCHAR(1000) 

DECLARE   
   @FK_NAME sysname,  
   @FK_OBJECTID INT,  
   @FK_DISABLED INT,  
   @FK_NOT_FOR_REPLICATION INT,  
   @DELETE_RULE    smallint,     
   @UPDATE_RULE    smallint,     
   @FKTABLE_NAME sysname,  
   @FKTABLE_OWNER sysname,  
   @PKTABLE_NAME sysname,  
   @PKTABLE_OWNER sysname,  
   @FKCOLUMN_NAME sysname,  
   @PKCOLUMN_NAME sysname,  
   @CONSTRAINT_COLID INT  


DECLARE cursor_fkeys CURSOR FOR   
   SELECT  Fk.name,  
           Fk.OBJECT_ID,   
           Fk.is_disabled,   
           Fk.is_not_for_replication,   
           Fk.delete_referential_action,   
           Fk.update_referential_action,   
           OBJECT_NAME(Fk.parent_object_id) AS Fk_table_name,   
           schema_name(Fk.schema_id) AS Fk_table_schema,   
           TbR.name AS Pk_table_name,   
           schema_name(TbR.schema_id) Pk_table_schema  
   FROM    sys.foreign_keys Fk LEFT OUTER JOIN   
           sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id --inner join   
   WHERE   TbR.name = @tableName  
           AND schema_name(TbR.schema_id) = @schemaName  

OPEN cursor_fkeys  

FETCH NEXT FROM   cursor_fkeys   
   INTO @FK_NAME,@FK_OBJECTID,  
       @FK_DISABLED,  
       @FK_NOT_FOR_REPLICATION,  
       @DELETE_RULE,     
       @UPDATE_RULE,     
       @FKTABLE_NAME,  
       @FKTABLE_OWNER,  
       @PKTABLE_NAME,  
       @PKTABLE_OWNER  

WHILE @@FETCH_STATUS = 0   
BEGIN   

   -- create statement for enabling FK  
   IF @operation = 'ENABLE'   
   BEGIN  
       SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME   
           + ']  CHECK CONSTRAINT [' + @FK_NAME + ']'  

      PRINT @cmd  
   END  

   -- create statement for disabling FK  
   IF @operation = 'DISABLE'  
   BEGIN     
       SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME   
           + ']  NOCHECK CONSTRAINT [' + @FK_NAME + ']'  

      PRINT @cmd  
   END  

   -- create statement for dropping FK and also for recreating FK  
   IF @operation = 'DROP'  
   BEGIN  

       -- drop statement  
       SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME   
       + ']  DROP CONSTRAINT [' + @FK_NAME + ']'     

      PRINT @cmd  

       -- create process  
       DECLARE @FKCOLUMNS VARCHAR(1000), @PKCOLUMNS VARCHAR(1000), @COUNTER INT  

       -- create cursor to get FK columns  
       DECLARE cursor_fkeyCols CURSOR FOR   
       SELECT  COL_NAME(Fk.parent_object_id, Fk_Cl.parent_column_id) AS Fk_col_name,   
               COL_NAME(Fk.referenced_object_id, Fk_Cl.referenced_column_id) AS Pk_col_name  
       FROM    sys.foreign_keys Fk LEFT OUTER JOIN   
               sys.tables TbR ON TbR.OBJECT_ID = Fk.referenced_object_id INNER JOIN   
               sys.foreign_key_columns Fk_Cl ON Fk_Cl.constraint_object_id = Fk.OBJECT_ID   
       WHERE   TbR.name = @tableName  
               AND schema_name(TbR.schema_id) = @schemaName  
               AND Fk_Cl.constraint_object_id = @FK_OBJECTID -- added 6/12/2008  
       ORDER BY Fk_Cl.constraint_column_id  

       OPEN cursor_fkeyCols  

       FETCH NEXT FROM    cursor_fkeyCols INTO @FKCOLUMN_NAME,@PKCOLUMN_NAME  

       SET @COUNTER = 1  
       SET @FKCOLUMNS = ''  
       SET @PKCOLUMNS = ''  
         
       WHILE @@FETCH_STATUS = 0   
       BEGIN   

           IF @COUNTER > 1   
           BEGIN  
               SET @FKCOLUMNS = @FKCOLUMNS + ','  
               SET @PKCOLUMNS = @PKCOLUMNS + ','  
           END  

           SET @FKCOLUMNS = @FKCOLUMNS + '[' + @FKCOLUMN_NAME + ']'  
           SET @PKCOLUMNS = @PKCOLUMNS + '[' + @PKCOLUMN_NAME + ']'  

           SET @COUNTER = @COUNTER + 1  
             
           FETCH NEXT FROM    cursor_fkeyCols INTO @FKCOLUMN_NAME,@PKCOLUMN_NAME  
       END  

       CLOSE cursor_fkeyCols   
       DEALLOCATE cursor_fkeyCols   

       -- generate create FK statement  
       SET @cmd = 'ALTER TABLE [' + @FKTABLE_OWNER + '].[' + @FKTABLE_NAME + ']  WITH ' +   
           CASE @FK_DISABLED   
               WHEN 0 THEN ' CHECK '  
               WHEN 1 THEN ' NOCHECK '  
           END +  ' ADD CONSTRAINT [' + @FK_NAME   
           + '] FOREIGN KEY (' + @FKCOLUMNS   
           + ') REFERENCES [' + @PKTABLE_OWNER + '].[' + @PKTABLE_NAME + '] ('   
           + @PKCOLUMNS + ') ON UPDATE ' +   
           CASE @UPDATE_RULE   
               WHEN 0 THEN ' NO ACTION '  
               WHEN 1 THEN ' CASCADE '   
               WHEN 2 THEN ' SET_NULL '   
               END + ' ON DELETE ' +   
           CASE @DELETE_RULE  
               WHEN 0 THEN ' NO ACTION '   
               WHEN 1 THEN ' CASCADE '   
               WHEN 2 THEN ' SET_NULL '   
               END + '' +  
           CASE @FK_NOT_FOR_REPLICATION  
               WHEN 0 THEN ''  
               WHEN 1 THEN ' NOT FOR REPLICATION '  
           END  

      PRINT @cmd  

   END  

   FETCH NEXT FROM    cursor_fkeys   
      INTO @FK_NAME,@FK_OBJECTID,  
           @FK_DISABLED,  
           @FK_NOT_FOR_REPLICATION,  
           @DELETE_RULE,     
           @UPDATE_RULE,     
           @FKTABLE_NAME,  
           @FKTABLE_OWNER,  
           @PKTABLE_NAME,  
           @PKTABLE_OWNER  
END  

CLOSE cursor_fkeys   
DEALLOCATE cursor_fkeys  

测试数据库:AdventureWorks

实例一:
Table: SpecialOfferProduct
Schema: Sales
Operation: DROP

输出:

ALTER TABLE [Sales].[SalesOrderDetail] DROP CONSTRAINT [FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID]
ALTER TABLE [Sales].[SalesOrderDetail] WITH NOCHECK ADD CONSTRAINT [FK_SalesOrderDetail_SpecialOfferProduct_SpecialOfferIDProductID] FOREIGN KEY ([SpecialOfferID],[ProductID]) REFERENCES [Sales].[SpecialOfferProduct] ([SpecialOfferID],[ProductID]) ON UPDATE NO ACTION ON DELETE NO ACTION

实例二:
Table: SpecialOfferProduct
Schema: Sales
Operation: DISABLE

输出:

ALTER TABLE [Sales].[Individual] NOCHECK CONSTRAINT [FK_Individual_Contact_ContactID]
ALTER TABLE [Sales].[SalesOrderHeader] NOCHECK CONSTRAINT [FK_SalesOrderHeader_Contact_ContactID]

ALTER TABLE [Sales].[StoreContact] NOCHECK CONSTRAINT [FK_StoreContact_Contact_ContactID]

ALTER TABLE [Purchasing].[VendorContact] NOCHECK CONSTRAINT [FK_VendorContact_Contact_ContactID]

ALTER TABLE [Sales].[ContactCreditCard] NOCHECK CONSTRAINT [FK_ContactCreditCard_Contact_ContactID]

ALTER TABLE [HumanResources].[Employee] NOCHECK CONSTRAINT [FK_Employee_Contact_ContactID]

Microsoft SQL Server 2005 安全设计课程笔记

这两天参加了 Designing Security for Microsoft SQL Server 2005 的培训,做个笔记。

一、SQL 服务器安全设计简介
1. 首要任务是设计好SQL服务器的安全规则
2. 参考标准为Common Criteria和C2

二、SQL服务器结构安全设计
1. 与企业现有的认证系统集成,例如AD
2. 制定服务器级的安全规则,评估高可靠性方案下的安全影响
3. 制定密码规则、确定服务帐号的权限、确定所有需要的服务
4. 制定防火墙规则
5. 规划好服务器的物理安全
6. 制定通讯规则,采用SSL或者IPSec加密传输数据
7. 制定安全监控标准。监控的内容包括:AD的安全策略、安全日志、域控制器的事件日志、本地策略、本地日志
8. 确定通知级别、通知人员

三、SQL 实例和数据库的安全策略设计
1. 授权和登录的安全策略
2. 强化代理服务、DDL事件,即时更新补丁和升级
3. 其次要有完善的监控手段

审计工具包括Microsoft的MBSA、SQL Server Surface Area Configuration 和 SQL Server 本身提供的工具,例如 Dynamic Management Views, DBCC 命令和存储进程。
监控工具包括SQL Server Profiler, System Monitor 和 SQL 本身提供的工具, 例如 sp_trace_create, sp_trace_setevent 和 sp_trace_setfilter,也可以通过系统 schema检查数据。

四、数据库安全设计中的数据加密

五、安全特例的设计

六、威胁和攻击的回应策略
分别针对病毒、蠕虫、DoS、SQL注入攻击的方案

Microsoft SQL Server 2005 数据库优化和排错课程笔记

这两天参加了SQL数据库优化和排错的培训,做个笔记。

一、SQL服务器性能监测方案
1. 使用SQL Server Profiler 和 System Monitor
2. 审计和比较测试结果

二、数据库和服务器性能故障的排错
1. SQLDiag 工具的使用

三、查询优化
1. 使用数据库 Engine Tuning Advisor

四、SQL 服务器连接故障的排错
1. Surface area configuration
2. SQL Server 2005 Endpoints

五、SQL 服务器数据故障的排错
1. 数据完整性
2. 通过Single-Page Restore 解决Torn Page的问题
Page_Verify 选项: 查找损坏的页面、TORN_PAGE_DETECTION 和 CHECKSUM

六、SQL 服务器并发故障的排错
1. SQL Server Latches
2. sp_blocker_pss80
3. Latch Wait Types
4. sys.dm_exec_sessions、sys.dm_exec_requests

MySQL 数据库双向复制、循环复制(镜像)

MySQL数据库复制、镜像、实时备份的文章中,主数据库A 的数据镜像到从数据库B,是单向的,网站的数据读写都必须在数据库A进行,结果会自动镜像到数据库B中。但是对数据库B的直接操作,不会影响数据库A。

对于双向数据库镜像,就是数据库A的数据变化要镜像到数据库B中,同时数据库B里的修改也要同时复制到数据库A里。
对于循环数据库镜像,就是多个数据库A、B、C、D等,对其中任一个数据库的修改,都要同时镜像到其它的数据库里。

应用:同一个网站的数据库和程序,可以放置在不同的主机上,在任一台主机上新增的订单、客户资料,都会同时加入其它的主机数据库里。

要实现双向或循环数据库镜像,首先要解决的就是防止数据库中自动递增(AUTO_INCREMENT)字段的冲突,以免多数据库各自生成一样的增量值。

下面以三台主机循环镜像为例,A是B的主镜像,B是C的主镜像,C是A的主镜像。三台主机上MySQL设置文件 /etc /my.cnf 中分别加入下面的参数:

#
主机一:美国主机 A, IP: 100.101.102.201
[mysqld]
server-id                      = 10
log-bin                         = mysql-bin
log-slave-updates
replicate-same-server-id       = 0
auto_increment_increment        = 10
auto_increment_offset          = 1
master-host                     = 100.101.102.203
master-user                    = repl_user
master-password                 = repl_password
report-host                     = 100.101.102.201

#
主机二:中国主机 B, IP: 100.101.102.202
[mysqld]
server-id                      = 20
log-bin                         = mysql-bin
log-slave-updates
replicate-same-server-id       = 0
auto_increment_increment        = 10
auto_increment_offset          = 2
master-host                     = 100.101.102.201
master-user                    = repl_user
master-password                 = repl_password
report-host                     = 100.101.102.202

#
主机三:本地主机 C, IP: 100.101.102.203
[mysqld]
server-id                      = 30
log-bin                         = mysql-bin
log-slave-updates
replicate-same-server-id       = 0
auto_increment_increment        = 10
auto_increment_offset          = 3
master-host                     = 100.101.102.202
master-user                    = repl_user
master-password                 = repl_password
report-host                     = 100.101.102.203

简单说明:
server-id:数据库标识,每个数据库标识必须唯一;
replicate-same-server-id:设置为0,防止数据循环更新;
auto_increment_increment:这是循环镜像里最重要的参数之一,表示自动增量为10,这将允许最多10台数据库加入这个循环镜像的阵列,而自动递增字段不会重复。
auto_increment_offset:这是循环镜像里最重要的参数之一,表示偏移值,每个数据库的偏移值必须唯一,且在1和auto_increment_increment之间。
master-host:主数据库服务器的IP;
master-user:用于连接主数据库的镜像用户名;
master-password:用于连接主数据库的镜像密码;
report-host:提供给主数据库用于反向连接的IP,因为主数据库有时无法正确判断从服务器的IP,所以这里最好填上从服务器自己的IP地址。

另外,有时只需要镜像某些数据库,可以在 my.cnf 中加入:
replicate-do-db = db_name1
replicate-do-db = db_name2
replicate-do-db = db_name3

这样就仅仅镜像 db_name1/db_name2/db_name3

如果只是某些数据库不要镜像,可以在 my.cnf 中加入:
replicate-ignore-db=db_name1
replicate-ignore-db=db_name2
replicate-ignore-db=db_name3

这样镜像时就忽略 db_name1/db_name2/db_name3 这三个数据库。