Выполнение запроса к данным csv, хранящимся в столбце ntext - PullRequest
0 голосов
/ 02 июня 2010

Скажите, что необработанный текст экспорта CSV и связанные с ним временные метки хранятся в базе данных, где одна запись эквивалентна одному экспорту.

У кого-нибудь есть способ выполнить запрос наФайл CSV хранится в этом поле без создания второго подключения к базе данных или экспорта данных в файл, а затем повторного открытия его с помощью текстового драйвера csv?

Предположим, что:

1) вы не можете записать физический файл на сервер в решении

2) вы не можете установить второе соединение с серверомw / OPENROWSET (серверы, имена пользователей и пароли меняются)

3) это должно быть решение на 100% SQL - должно быть в состоянии работать как SP

4), которое вам нужно толькодля работы с одной записью за раз - решение не должно учитывать выбор из нескольких CSV-файлов, хранящихся в БД.

Ответы [ 2 ]

0 голосов
/ 02 июня 2010

Мое решение было бы создать 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 голосов
/ 02 июня 2010

Вы можете настроить ряд пользовательских функций, которые могут анализировать столбец. Скорее всего, он будет медленным и совсем не будет устойчивым.

В качестве примера (без реальной проверки ошибок и т. Д. И только с минимальной проверкой):

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')
...