2010-06-02 45 views
0

說明CSV導出的原始文本和相關時間戳存儲在數據庫中,其中一個記錄等同於一個導出。對存儲在ntext列中的csv數據執行查詢

有沒有人有辦法上執行,而無需創建一個到數據庫的第二個連接或將數據導出到一個文件,然後使用CSV文本驅動程序重新打開它存儲在該領域的CSV文件的查詢?

假設:

1)你不能在溶液

2)寫出的物理文件到服務器可以不是第二連接至服務器瓦特/ OPENROWSET(服務器,用戶名&密碼變更)

3),它必須是一個100%的SQL解決方案 - 必須能夠運行爲SP

4),你只需要在時間與一個記錄工作 - 該解決方案不需要考慮sele來自存儲在數據庫中的多個csv文件。

+0

究竟是什麼構成「執行查詢」? – 2010-06-02 17:07:49

+0

CSV數據是否具有相同的行結構結構?該結構是否預定義? – 2010-06-02 18:01:22

+0

@PK CSV數據將具有行到行的相同結構,並且是預定義的。 @Tom H.假設它只需要處理簡單的SELECT(沒有子查詢,並且絕對不會改變csv數據中的記錄) – seraphym 2010-06-02 18:05:36

回答

0

我的解決方案是創建一個UDF將CSV數據解析成表變量。然後,在SP中,檢索CSV,將其傳遞給UDF,然後針對表變量運行查詢。

首先,創建一個UDF從CSV值返回表(使用CHAR(13),以確定新的生產線,可能需要改變你的數據進行工作):

CREATE FUNCTION [dbo].[fnParseCSV] (@InputString NVARCHAR(MAX), @Delimiter NCHAR(1) = ',') 
RETURNS @tbl TABLE (ID int, Val NVARCHAR(64)) AS 
BEGIN 
    declare @singleLine nvarchar(max) 
    declare @id int 
    declare @val varchar(64) 

    WHILE LEN(@InputString) > 0 BEGIN 
     IF CHARINDEX(char(13), @InputString) > 0 BEGIN 
      SELECT @singleLine = SUBSTRING(@InputString, 1, CHARINDEX(char(13), @InputString) - 1) 
      IF CHARINDEX(@Delimiter, @singleline) > 0 BEGIN 
       SELECT @id = convert(int, SUBSTRING(@singleline, 1, CHARINDEX(@Delimiter, @singleline) - 1)) 
       SELECT @val = RIGHT(@singleline, LEN(@singleline) - CHARINDEX(@Delimiter, @singleline)) 
       INSERT INTO @tbl (id, val) values (@id, @val) 
      END 

      SELECT @InputString = RIGHT(@InputString, LEN(@InputString) - CHARINDEX(char(13), @InputString)) 
     END 
     ELSE 
     BEGIN 
      IF CHARINDEX(@Delimiter, @inputString) > 0 
      BEGIN 
       SELECT @id = convert(int, SUBSTRING(@inputString, 1, CHARINDEX(@Delimiter, @inputString) - 1)) 
       SELECT @val = RIGHT(@inputString, LEN(@inputString) - CHARINDEX(@Delimiter, @inputString)) 
       INSERT INTO @tbl (id, val) values (@id, @val) 
      END 
      set @inputString = '' 
     END 
    END 
    RETURN 
END 

然後運行鍼對該輸出的查詢:

select * from dbo.fnParseCsv('123,val1' + char(13) + '456,val2' + CHAR(13) + '789,val3', ',') 
0

您可以設置一系列可以通過列解析的用戶定義函數。這可能會很緩慢,根本不會很健壯。

彷彿一個例子(沒有真正的錯誤檢查等,並且僅最低限度地測試):

IF OBJECT_ID('dbo.Test_CSV_Search') IS NOT NULL 
    DROP TABLE dbo.Test_CSV_Search 
GO 
CREATE TABLE dbo.Test_CSV_Search 
(
    my_id INT IDENTITY NOT NULL, 
    txt  VARCHAR(MAX) NOT NULL, 
    CONSTRAINT PK_Test_CSV_Search PRIMARY KEY CLUSTERED (my_id) 
) 
GO 
INSERT INTO dbo.Test_CSV_Search (txt) VALUES ('11, 12, 13, 14,15,16 
21,22, 23,24, 25,26 
31,22,33,34,35,36') 
GO 
IF OBJECT_ID('dbo.Get_CSV_Row') IS NOT NULL 
    DROP FUNCTION dbo.Get_CSV_Row 
GO 
CREATE FUNCTION dbo.Get_CSV_Row 
(@my_id INT, @col_num SMALLINT, @search_value VARCHAR(100)) 
RETURNS @results TABLE (row_num INT, row_txt VARCHAR(MAX)) 
AS 
BEGIN 
    DECLARE 
     @csv_txt VARCHAR(MAX), 
     @full_row VARCHAR(MAX), 
     @start_pos INT, 
     @end_pos INT, 
     @col_txt VARCHAR(100), 
     @cur_col SMALLINT, 
     @line_start INT, 
     @line_end INT, 
     @row_num INT 

    SELECT @csv_txt = txt + CHAR(10) FROM dbo.Test_CSV_Search WHERE my_id = @my_id 

    SELECT 
     @line_start = 1, 
     @cur_col = 1, 
     @start_pos = 1, 
     @row_num = 1 

    WHILE (CHARINDEX(CHAR(10), @csv_txt, @line_start) > 0) 
    BEGIN 
     SELECT 
      @line_end = CHARINDEX(CHAR(10), @csv_txt, @line_start), 
      @end_pos = CHARINDEX(',', @csv_txt, @start_pos) 

     WHILE (@cur_col < @col_num) 
     BEGIN 
      SET @start_pos = @end_pos + 1 
      SET @end_pos = CHARINDEX(',', @csv_txt, @start_pos) 
      SET @cur_col = @cur_col + 1 
     END 

     IF (RTRIM(LTRIM(SUBSTRING(@csv_txt, @start_pos, @end_pos - @start_pos))) = @search_value) 
     BEGIN 
      INSERT INTO @results (row_num, row_txt) VALUES (@row_num, RTRIM(LTRIM(SUBSTRING(@csv_txt, @line_start, @line_end - @line_start)))) 
     END 

     SELECT 
      @line_start = @line_end + 1, 
      @start_pos = @line_end + 1, 
      @cur_col = 1, 
      @row_num = @row_num + 1 
    END 

    RETURN 
END 
GO 

SELECT * FROM dbo.Get_CSV_Row(1, 1, '11')