当前,我在表中有一列定义为文本,数据格式为XML。
示例数据为:
<Attributes><Default>0</Default><Table>0=Monday
1=Tuesday
2=Wednesday
3=Thursday
4=Friday
5=Saturday
-1=Sunday
</Table><Visibility>0</Visibility></Attributes>
此列需要连接到另一个表,该表的“工作日”列为“星期一”,值为0。我需要能够研究这个XML结构并在星期一返回。
表1结构:
CREATE TABLE [CNF_Right]
(
[RightId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[Attribute] [text] NULL
)
表1数据:
RightID Attribute
-----------------------------------------------------
1 <Attributes><Default>0</Default>
<Table>0=Monday
1=Tuesday
2=Wednesday
3=Thursday
4=Friday
5=Saturday
-1=Sunday
</Table>
<Visibility>0</Visibility>
</Attributes>
表2的结构:
CREATE TABLE [DATA_Right]
(
[RightDataId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[WeekDay] [int] NOT NULL
)
表2数据:
RightDataID WeekDay
-------------------------------
1 0
2 -1
3 5
当我加入这两个时,我想返回
Rightid RightDataID Weekday WeekDayDescription
-------------------------------------------------------
1 1 0 Monday
1 2 -1 Sunday
1 3 5 Saturday
任何帮助将不胜感激。
TIA
答案 0 :(得分:0)
正如我之前在评论中告诉您的那样,这种设计很糟糕,但这是您必须忍受的东西...
尝试一下:
USE master;
GO
CREATE DATABASE dbTest;
GO
Use dbTest;
GO
CREATE TABLE [CNF_Right]
(
[RightId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[Attribute] [text] NULL
);
CREATE TABLE [DATA_Right]
(
[RightDataId] [int] IDENTITY(1,1) NOT FOR REPLICATION NOT NULL,
[WeekDay] [int] NOT NULL
);
GO
INSERT INTO [CNF_Right](Attribute) VALUES
('<Attributes><Default>0</Default><Table>0=Monday
1=Tuesday
2=Wednesday
3=Thursday
4=Friday
5=Saturday
-1=Sunday
</Table><Visibility>0</Visibility></Attributes>');
INSERT INTO [DATA_Right]([WeekDay])
VALUES(0),(-1),(5);
GO
CREATE FUNCTION dbo.GetWeekdayList(@RightId INT)
RETURNS TABLE
AS
RETURN
WITH GetContent(TableContent) AS
(
SELECT CAST(CAST(r.Attribute AS VARCHAR(MAX)) AS XML).value('(/Attributes/Table/text())[1]','nvarchar(max)')
FROM [CNF_Right] r
WHERE r.RightId=@RightId
)
,SplitContent(AsXml) AS
(
SELECT CAST('<x><y>' + REPLACE(REPLACE(REPLACE(REPLACE(gc.TableContent,CHAR(13),CHAR(10)),CHAR(10)+CHAR(10),CHAR(10)),'=','</y><y>'),CHAR(10),'</y></x><x><y>') + '</y></x>' AS XML)
FROM GetContent gc
)
SELECT x.value('y[1]','int') AS WeekdayIndex
,x.value('y[2]','nvarchar(max)') AS WeekdayName
FROM SplitContent sc
CROSS APPLY sc.AsXml.nodes('/x[y/text()]') A(x);
GO
SELECT *
FROM [DATA_Right] dr
INNER JOIN dbo.GetWeekdayList(1) AS wl ON wl.WeekdayIndex=dr.[WeekDay]
GO
USE master;
GO
--Careful with real data
--DROP DATABASE dbTest;
GO
创建测试数据库后,我使用您的命令来创建两个表。
然后将XML和权限值插入这些表中。
魔术是在内联表值函数dbo.GetWeekdayList()
中完成的。此函数会将TEXT
强制转换为VARCHAR(MAX)
,并将其强制转换为XML
。为了能够使用.value()
方法在XML中检索值,需要这样做。
结果是值列表,它是一个带有换行符和=
字符的大字符串。
第二步,使用XML技巧拆分此字符串,而最后的SELECT
将返回工作日的名称和索引作为派生表。
最终查询将加入 iTVF ,就像它是一个表一样。
这会很慢。
TEXT
已过时,以后的版本将不再支持。
XML必须反复转换-操作非常昂贵。
必须使用大量昂贵的字符串操作,强制转换和XML操作一遍又一遍地创建派生表。
所有这些都是在可怜的小型数据库服务器上计算的。您的DBA将爱您...
我建议将这些数据写入经过适当设计的帮助程序表中,并将其加入。
从长远来看,这种设计应该完全改变...