我在sql表中有一个字段,但是我需要通过charindex
来解析它,但是需要注意的是,我不知道有多少个字段。
字段数据如下所示:
(Image: "filename=a.jpg"), (Image: "filename=b.jpg")
但是问题是我不确定该字符串中将有多少个文件名,因此我需要动态地构建此文件名,该文件名可以是1或100。
有什么建议吗?
谢谢
答案 0 :(得分:0)
由于您无法预先知道将从每个值中提取多少个值,因此建议将结果表示为记录,而不是列。
如果您使用的是SQL Server 2016或更高版本,则可以使用功能STRING_SPLIT()
将CSV部分转换为记录。然后,SUBSTRING()
和CHARINDEX()
可用于提取相关信息:
声明@t表([txt] varchar(200)) 插入@t VALUES('(图像:“ filename = a.jpg”),(图像:“ filename = b.jpg”)')
SELECT value, SUBSTRING(
value,
CHARINDEX('=', value) + 1,
LEN(value) - CHARINDEX('=', value) - 2
)
FROM @t t
CROSS APPLY STRING_SPLIT(t.txt , ',')
DECLARE @t table ([txt] varchar(200))
INSERT INTO @t VALUES ('(Image: "filename=a.jpg"),(Image: "filename=b.jpg")')
SELECT value, SUBSTRING(
value,
CHARINDEX('=', value) + 1,
LEN(value) - CHARINDEX('=', value) - 2
)
FROM @t t
CROSS APPLY STRING_SPLIT(t.txt , ',')
GO
value | (No column name) :------------------------ | :--------------- (Image: "filename=a.jpg") | a.jpg (Image: "filename=b.jpg") | b.jpg
NB:这假定要提取的值始终位于第一个等号之后,直到字符串末尾的2个字符为止。如果模式不同,则可能需要调整SUBSTRING()
/ CHARINDEX()
调用。
答案 1 :(得分:0)
真正的问题是:这破坏了 1.NF 。您永远不要在一个单元中存储多个数据。这样的CSV格式令人不寒而栗,您确实应该使用相关的边桌来一个存储图像提示。
尽管如此,这可以解决:
-一个样机表
DECLARE @mockup TABLE(ID INT IDENTITY,YourString VARCHAR(1000));
INSERT INTO @mockup VALUES
('(Image: "filename=a.jpg"), (Image: "filename=b.jpg") ')
,('(Image: "filename=aa.jpg"), (Image: "filename=bb.jpg"), (Image: "filename=cc.jpg"), (Image: "filename=dd.jpg"), (Image: "filename=ee.jpg")');
-通过其位置选择一个元素:
DECLARE @position INT=2;
SELECT CAST('<x>' + REPLACE(t.YourString,',','</x><x>') + '</x>' AS XML)
.value('/x[position()=sql:variable("@position")][1]','nvarchar(max)')
FROM @mockup t;
诀窍是,将字符串转换为XML,然后使用XQuery
通过位置获取所需的元素。中间XML如下所示:
<x>(Image: "filename=a.jpg")</x>
<x> (Image: "filename=b.jpg") </x>
您可以使用更多替代品和L/RTRIM()
使其更清洁。
如果您想创建一个干净的边桌,并且需要将所有数据整齐地分开,则可以使用更多相同的东西:
SELECT CAST('<x><y><z>'
+ REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
t.YourString,'(','') --no opening paranthesis
,')','') --no closing paranthesis
,'"','') --no quotes
,' ','') --no blanks
,'=','</z><z>') --Split at "="
,':','</z></y><y><z>') --Split at ":"
,',','</z></y></x><x><y><z>') --Split at ","
+ '</z></y></x>' AS XML)
FROM @mockup t;
这将返回
<x>
<y>
<z>Image</z>
</y>
<y>
<z>filename</z>
<z>a.jpg</z>
</y>
</x>
<x>
<y>
<z>Image</z>
</y>
<y>
<z>filename</z>
<z>b.jpg</z>
</y>
</x>
这样,您将获得一个干净的EAV表(
WITH Casted AS
(
SELECT ID
,CAST('<x><y><z>'
+ REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
t.YourString,'(','')
,')','')
,'"','')
,' ','')
,'=','</z><z>')
,':','</z></y><y><z>')
,',','</z></y></x><x><y><z>')
+ '</z></y></x>' AS XML) AS CastedToXml
FROM @mockup t
)
SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS ID
,ID AS oldId
,eachElement.value('y[1]/z[1]','varchar(max)') AS DataType
,eachElement.value('y[2]/z[1]','varchar(max)') AS ContentType
,eachElement.value('y[2]/z[2]','varchar(max)') AS Content
FROM Casted
CROSS APPLY CastedToXml.nodes('/x') A(eachElement)
结果
+----+-------+----------+-------------+---------+
| ID | oldId | DataType | ContentType | Content |
+----+-------+----------+-------------+---------+
| 1 | 1 | Image | filename | a.jpg |
+----+-------+----------+-------------+---------+
| 2 | 1 | Image | filename | b.jpg |
+----+-------+----------+-------------+---------+
| 3 | 2 | Image | filename | aa.jpg |
+----+-------+----------+-------------+---------+
| 4 | 2 | Image | filename | bb.jpg |
+----+-------+----------+-------------+---------+
| 5 | 2 | Image | filename | cc.jpg |
+----+-------+----------+-------------+---------+
| 6 | 2 | Image | filename | dd.jpg |
+----+-------+----------+-------------+---------+
| 7 | 2 | Image | filename | ee.jpg |
+----+-------+----------+-------------+---------+
答案 2 :(得分:0)
我使用了表值函数
ALTER FUNCTION [dbo].[Fn_sqllist_to_table](@list AS VARCHAR(8000),
@delim AS VARCHAR(10))
RETURNS @listTable TABLE(
Position INT,
Value VARCHAR(8000))
AS
BEGIN
DECLARE @myPos INT
SET @myPos = 1
WHILE Charindex(@delim, @list) > 0
BEGIN
INSERT INTO @listTable
(Position,Value)
VALUES (@myPos,LEFT(@list, Charindex(@delim, @list) - 1))
SET @myPos = @myPos + 1
IF Charindex(@delim, @list) = Len(@list)
INSERT INTO @listTable
(Position,Value)
VALUES (@myPos,'')
SET @list = RIGHT(@list, Len(@list) - Charindex(@delim, @list))
END
IF Len(@list) > 0
INSERT INTO @listTable
(Position,Value)
VALUES (@myPos,@list)
RETURN
END
通过
调用select * into #test from tableX as T
cross apply [Fn_sqllist_to_table](fieldname,'(')
然后将值细分为最终表