假设CSV导出的原始文本和关联的时间戳存储在数据库中,其中一条记录相当于一个导出。
是否有人可以对存储在该字段中的CSV文件执行查询,而无需创建与数据库的第二个连接或将数据导出到文件,然后使用csv文本重新打开它驱动程序?
假设:
1)您无法在解决方案中将物理文件写入服务器
2)你不能第二次连接服务器w / OPENROWSET(服务器,用户名和密码更改)
3)它必须是100%SQL解决方案 - 必须能够作为SP运行
4)您只需要一次处理一条记录 - 该解决方案无需考虑从存储在数据库中的多个csv文件中进行选择。
答案 0 :(得分: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')
答案 1 :(得分: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', ',')