Domanda

Dire che il testo grezzo delle esportazioni CSV e un timestamp associati vengono memorizzati in un database, in cui un record equivale a un export.

Qualcuno ha un modo per eseguire una query sul file CSV memorizzato in quel campo , senza creare una seconda connessione al database o esportare i dati in un file e poi riaprire usando il testo csv autista?

Si supponga che:

1) non è possibile scrivere un file fisico sul server nella soluzione

2) non è possibile una seconda connessione al server w / OPENROWSET (server, i nomi utente e le password cambia)

3) che deve essere una soluzione SQL 100% - deve essere in grado di essere eseguito come un SP

4) che avete solo bisogno di lavorare con un record alla volta -. La soluzione non c'è bisogno di conto per la selezione da più file csv memorizzati nel DB

È stato utile?

Soluzione

La mia soluzione sarebbe quella di creare una funzione definita dall'utente che analizzare i dati CSV in una variabile di tabella. Poi, nel SP, recuperare il CSV, passarlo al UDF, quindi eseguire la query sulla variabile di tabella.

In primo luogo, creare un'UDF per restituire un tavolo dal valore CSV (usi CHAR (13) per determinare nuove linee, potrebbe essere necessario essere modificato per operare con i dati):

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

Quindi eseguire la query che in uscita:

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

Altri suggerimenti

È possibile impostare una serie di funzioni definite dall'utente, che in grado di analizzare attraverso la colonna. Sarebbe probabilmente essere lento e non sarebbe affidabile a tutti.

Per fare un esempio se (con nessun controllo vero e proprio errore, ecc e solo in minima parte testato):

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')
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top