Sql 有没有比数据透视表或使用XML和节点更有效的滑动列的方法
我想知道是否还有其他方法可以分割列,或者比这两种方法更好的方法 我要写一些代码,这样我们可以说同一种语言Sql 有没有比数据透视表或使用XML和节点更有效的滑动列的方法,sql,sql-server,Sql,Sql Server,我想知道是否还有其他方法可以分割列,或者比这两种方法更好的方法 我要写一些代码,这样我们可以说同一种语言 --CREATING TABLE CREATE TABLE BOOKS( ID VARCHAR(MAX) NULL ) /* BOOKS PRODUCTID, NAME, PAGES, WEIGHT, SIZE, TYPE */ INSERT INTO BOOKS (ID) VALUES('B001,INTRODUCTION TO SQL,500,100G,MID,TECH')
--CREATING TABLE
CREATE TABLE BOOKS(
ID VARCHAR(MAX) NULL
)
/*
BOOKS
PRODUCTID, NAME, PAGES, WEIGHT, SIZE, TYPE
*/
INSERT INTO BOOKS (ID)
VALUES('B001,INTRODUCTION TO SQL,500,100G,MID,TECH')
,('B002,ADVANCED SQL SERVER PRACTICES,200,200G,BIG,TECH')
,('B003,SQL SERVER PERFORMANCE,1000,500G,BIG,TECH')
,('B004,SQL SERVER MANUAL,50,30G,SMALL,TECH')
,('B004,SQL SERVER MANUAL,50,30G,SMALL,TECH')
这将是我的演示表,正如您所看到的,我有一个带有逗号分隔值的表
为了分割这些值,我将使用pivot和CTE组合
/*PIVOTING TABLE, ASIGNING A RN TO COLUMNS AND GETTING BACK VALUES*/
WITH C AS(
SELECT ID
,value
,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY (SELECT NULL)) as rn
FROM BOOKS BO
CROSS APPLY STRING_SPLIT(ID, ',') AS BK
)
SELECT ID
,[1] AS PRODUCTID
,[2] AS NAME
,[3] AS PAGES
,[4] AS WEIGHT
,[5] AS SIZE
,[6] AS TYPE
FROM C
PIVOT(
MAX(VALUE)
FOR RN IN([1],[2],[3],[4],[5],[6])
) as PVT
它工作正常,但在本例中,它返回的字符串顺序不保证为Ex,1,2,3,4。column1=1,column2=3 column3=2 column4=4,我希望得到1,2,3,4
另一个是众所周知的stackoverflow,它使用XML和节点
SELECT DISTINCT
S.a.value('(/H/r)[1]', 'VARCHAR(100)') AS PRODUCTID
,S.a.value('(/H/r)[2]', 'VARCHAR(100)') AS NAME
, S.a.value('(/H/r)[3]', 'VARCHAR(100)') AS PAGES
, S.a.value('(/H/r)[4]', 'VARCHAR(100)') AS WEIGHT
, S.a.value('(/H/r)[5]', 'VARCHAR(100)') AS SIZE
, S.a.value('(/H/r)[6]', 'VARCHAR(100)') AS TYPE
FROM
(
SELECT *,CAST (N'<H><r>' + REPLACE(ID, ',', '</r><r>')
+ '</r></H>' AS XML) AS [vals]
FROM BOOKS) d
CROSS APPLY d.[vals].nodes('/H/r') S(a)
另一个是众所周知的stackoverflow,它使用XML和节点
SELECT DISTINCT
S.a.value('(/H/r)[1]', 'VARCHAR(100)') AS PRODUCTID
,S.a.value('(/H/r)[2]', 'VARCHAR(100)') AS NAME
, S.a.value('(/H/r)[3]', 'VARCHAR(100)') AS PAGES
, S.a.value('(/H/r)[4]', 'VARCHAR(100)') AS WEIGHT
, S.a.value('(/H/r)[5]', 'VARCHAR(100)') AS SIZE
, S.a.value('(/H/r)[6]', 'VARCHAR(100)') AS TYPE
FROM
(
SELECT *,CAST (N'<H><r>' + REPLACE(ID, ',', '</r><r>')
+ '</r></H>' AS XML) AS [vals]
FROM BOOKS) d
CROSS APPLY d.[vals].nodes('/H/r') S(a)
它也能像预期的那样工作,但别误会我的意思,如果你不在初级水平以上,它很难解释,也有点让人困惑
还有什么更好的方法可以在sql server中拆分列,microsoft是否为此实现了一个新功能,或者您知道其他方法吗 就我个人而言,我的方法是将该值视为一个带分隔符的项,然后使用交叉表将其透视。由于顺序位置很重要,而且字符串_SPLIT不能保证这一点,因此在这里是一个更好的选择:
SELECT MAX(CASE DS.ItemNumber WHEN 1 THEN NULLIF(DS.Item,'') END) AS PRODUCTID,
MAX(CASE DS.ItemNumber WHEN 2 THEN NULLIF(DS.Item,'') END) AS [NAME],
MAX(CASE DS.ItemNumber WHEN 3 THEN NULLIF(DS.Item,'') END) AS PAGES,
MAX(CASE DS.ItemNumber WHEN 4 THEN NULLIF(DS.Item,'') END) AS WEIGHT,
MAX(CASE DS.ItemNumber WHEN 5 THEN NULLIF(DS.Item,'') END) AS SIZE,
MAX(CASE DS.ItemNumber WHEN 6 THEN NULLIF(DS.Item,'') END) AS [TYPE]
FROM dbo.BOOKS B
CROSS APPLY dbo.DelimitedSplit8K_LEAD(B.ID,',') DS
GROUP BY B.ID;
就我个人而言,我的方法是将该值视为一个分隔的项,然后使用交叉表对其进行透视。由于顺序位置很重要,而且字符串_SPLIT不能保证这一点,因此在这里是一个更好的选择:
SELECT MAX(CASE DS.ItemNumber WHEN 1 THEN NULLIF(DS.Item,'') END) AS PRODUCTID,
MAX(CASE DS.ItemNumber WHEN 2 THEN NULLIF(DS.Item,'') END) AS [NAME],
MAX(CASE DS.ItemNumber WHEN 3 THEN NULLIF(DS.Item,'') END) AS PAGES,
MAX(CASE DS.ItemNumber WHEN 4 THEN NULLIF(DS.Item,'') END) AS WEIGHT,
MAX(CASE DS.ItemNumber WHEN 5 THEN NULLIF(DS.Item,'') END) AS SIZE,
MAX(CASE DS.ItemNumber WHEN 6 THEN NULLIF(DS.Item,'') END) AS [TYPE]
FROM dbo.BOOKS B
CROSS APPLY dbo.DelimitedSplit8K_LEAD(B.ID,',') DS
GROUP BY B.ID;
如果2016+,另一个选项是JSON JSON似乎优于XML,特别是在选择片段和选择值方面 范例
如果2016+,另一个选项是JSON JSON似乎优于XML,特别是在选择片段和选择值方面 范例
为什么要存储分隔数据?数据首先应该是6个独立的列,因此您的表格应该有6列,而不是1列。我在工作中处理客户数据时多次遇到过这种情况,请相信我,在进行数据分析时,数据并不总是专门结构化的。请参阅本文。它描述了一个也返回列顺序的拆分器函数。你应该看看它的改进版本@user1443098:那是我,@user1443098,不是Alvaro;是的,Eirikur在发表之前,对Jeff谈了很多关于这个函数的事情,并表示了他的祝福。在我看来,这两个函数是SSC社区的一个很好的例子。为什么要存储分隔数据?数据首先应该是6个独立的列,因此您的表格应该有6列,而不是1列。我在工作中处理客户数据时多次遇到过这种情况,请相信我,在进行数据分析时,数据并不总是专门结构化的。请参阅本文。它描述了一个也返回列顺序的拆分器函数。你应该看看它的改进版本@user1443098:那是我,@user1443098,不是Alvaro;是的,Eirikur在发表之前,对Jeff谈了很多关于这个函数的事情,并表示了他的祝福。在我看来,这两个功能是SSC社区的一个很好的例子。你有没有重新设置它?@user1443098我想我不必这样做。尽管Larnu的函数令人印象深刻,但它仍然是一个表值函数和聚合,而不是本机函数!我认为Jeff的基准测试表明情况并非总是如此。就个人而言,在我的家庭工作站i7 8700 32GB RAM上,我发现带630行分隔符的DSPLIT8K_需要10毫秒,而JSON解决方案平均需要16毫秒。3130时48分对83分。奇怪的是,在15000行时,它们在PAR上,然后在80000行,JSON慢得多,在100MS~VS2000毫秒之间。在400000行时,JSON慢了几秒钟。本机函数并不总是更好。例如,看看糟糕的格式函数:@Larnu格式化功能是一个廉价的镜头:你把它重新放在板凳上了吗?@user1443098我想我不必这么做。尽管Larnu的函数令人印象深刻,但它仍然是一个表值函数和聚合,而不是本机函数!我认为Jeff的基准测试表明情况并非总是如此。就个人而言,在我的家庭工作站i7 8700 32GB RAM上,我发现带630行分隔符的DSPLIT8K_需要10毫秒,而JSON解决方案平均需要16毫秒。3130时48分对83分。奇怪的是,在15000行时,它们在PAR上,然后在80000行,JSON慢得多,在100MS~VS2000毫秒之间。在400000行时,JSON慢了几秒钟。本机函数并不总是更好。例如,看看糟糕的格式函数:@Larnu格式化功能是一个廉价的功能: