SSIS OPENROWSET查询平面文件

时间:2016-09-21 20:57:27

标签: sql sql-server ssis

我目前有一个名为InvoiceFileName的变量名,它通过foreach循环创建.csv文件。然后将.csv列表输出到文件夹 然后,我将需要查询每个.csv文件,以选择每个.csv的标头和第一行数据。 我相信我需要使用OPENROWSET来查询.csv。我有两个问题。

  1. 查询变量名称InvoiceFileName。
  2. 的语法是什么
  3. 是否可以选择标题字段和第一行数据OPENROWSET而无需插入表格。
  4. 下面是一个简单的OPENROWSET,它只提供文件的标题。

    SELECT 
    top 1 *
    FROM OPENROWSET(BULK N'\\myservername\f$\reports\Invoices\CokeFiles\54ASBSd.csv', SINGLE_CLOB) AS Report 
    

2 个答案:

答案 0 :(得分:1)

您对数据库有什么样的权限?如果您拥有或者可以获得略微提升的权限,您可以使用BULK INSERTxp_cmdShell来完成此任务,但是像@scsimon所说,您将不得不使用动态SQL。这是一个简单的例子:

-----------------------------------------------------------------------------------------------------
-- Set up your variables
-----------------------------------------------------------------------------------------------------
DECLARE 
    @folderPath AS VARCHAR(100) = '\\some\folder\path\here\',
    @cmd AS VARCHAR(150), -- Will populate this with a command to get a list of files in a directory
    @InvoiceFileName AS VARCHAR(100), -- Will be used in cursor loop
    @targetTable AS VARCHAR(50) = 'SomeTable',
    @fieldTerminator AS CHAR(1) = ',',
    @rowTerminator AS CHAR(2) = '\n'
-----------------------------------------------------------------------------------------------------
-- Create a temp table to store the file names
-----------------------------------------------------------------------------------------------------
IF OBJECT_ID('tempdb..#FILE_LIST') IS NOT NULL
    DROP TABLE #FILE_LIST
--
CREATE TABLE #FILE_LIST(FILE_NAME VARCHAR(255))

-----------------------------------------------------------------------------------------------------
-- Get a list of the files and store them in the temp table:
-- NOTE: this DOES require elevated permissions
-----------------------------------------------------------------------------------------------------
SET @cmd = 'dir "' + @folderPath + '" /b'
--
INSERT INTO #FILE_LIST(FILE_NAME)
EXEC Master..xp_cmdShell @cmd

--------------------------------------------------------------------------------
-- Here we remove any null values
--------------------------------------------------------------------------------
DELETE #FILE_LIST WHERE FILE_NAME IS NULL

-----------------------------------------------------------------------------------------------------
-- Set up our cursor and loop through the files 
-----------------------------------------------------------------------------------------------------
DECLARE c1 CURSOR FOR SELECT FILE_NAME FROM #FILE_LIST
OPEN c1
FETCH NEXT FROM c1 INTO @InvoiceFileName
WHILE @@FETCH_STATUS <> -1
    BEGIN -- Begin WHILE loop
        BEGIN TRY
            -- Bulk insert won't take a variable name, so dynamically generate the 
            --  SQL statement and execute it instead:
            SET @sql = 'BULK INSERT ' + @targetTable + ' FROM ''' + @InvoiceFileName + ''' '
                + '     WITH ( 
                        FIELDTERMINATOR = ''' + @fieldTerminator + ''', 
                        ROWTERMINATOR = ''' + @rowTerminator + ''', 
                        FIRSTROW = 1,
                        LASTROW = 2
                    ) '
            EXEC (@sql)
        END TRY
        BEGIN CATCH
            -- Handle errors here
        END CATCH
        -- Continue your loop
        FETCH NEXT FROM c1 INTO @path,@filename
    END -- End WHILE loop

-- Do what you need to do here with the data in your target table

一些免责声明:

  1. 我没有测试过这段代码。只是从过去使用的稍微复杂的过程中复制而来,这种过程适用于这种情况。
  2. 您需要提升BULK INSERTxp_cmdShell的私有权限。
  3. 我知道人们不赞成使用xp_cmdShell(并且有充分的理由),但这是一个快速而肮脏的解决方案,对您的环境是什么做出了很多假设。
  4. 这假设您在获取变量中的每个文件时都没有抓取数据。如果是,您可以跳过此代码的第一部分。
  5. 此代码还假设您在自己看到的try / catch块之外的其他位置执行自己的错误处理。为简单起见,我省略了很多。

要通过SSIS执行此操作,理想情况下您可能需要use a format file for the bulk operation,但您必须始终格式化文件并删除SINGLE_CLOB选项。一个真正的hacky和非理想的方法是做这样的事情:

假设您的文件包含以下数据:

Col1,Col2,Col3,Col4
Here's,The,First,Line
Here's,The,Second,Line
Here's,The,Third,Line
Here's,The,Fourth,Line

然后你基本上可以解析这样的数据:

SELECT SUBSTRING(OnlyColumn, 0, CHARINDEX(CHAR(10), OnlyColumn, CHARINDEX(CHAR(10), OnlyColumn, 0)+1) )
FROM OPENROWSET(BULK '\\location\of\myFile.csv', SINGLE_CLOB) AS Report (OnlyColumn)

你的结果就是这样:

Col1,Col2,Col3,Col4  Here's,The,First,Line 

这显然取决于您的行结尾是否一致,但如果您希望结果在单个列和单行中(就像使用SINGLE_CLOB选项的批量操作的行为一样),那么这应该可以满足您的需要。

您可以查看this SO post上的解决方案,了解有关如何将SSIS变量值作为参数传递给查询的信息。

答案 1 :(得分:0)

使用Foreach循环容器查询文件夹中的所有文件。您可以使用通配符作为文件名,也可以使用DTS中的变量来设置组件的属性。

在循环容器中放置数据流任务,其中包含源文件连接,转换和目标。

您可以通过将属性设置为DTS中的变量来修改所有这些对象的文件名和路径。

在循环内部使用Expresion Task,您可以更改CSV文件连接的路径。

Foreach Loop Editor