sql-server – SQL Server:临时收集聚合中的值,并在同一查询中
发布时间:2020-12-12 07:08:51 所属栏目:MsSql教程 来源:网络整理
导读:如何在T-SQL中累积值? AFAIK没有ARRAY类型. 我想重新使用相同查询中的值,如使用 array_agg()在此PostgreSQL示例中演示的那样. SELECT a[1] || a[i] AS foo,a[2] || a[5] AS bar -- assuming we have = 5 rows for simplicityFROM ( SELECT array_agg(text_co
如何在T-SQL中累积值? AFAIK没有ARRAY类型.
我想重新使用相同查询中的值,如使用 array_agg()在此PostgreSQL示例中演示的那样. SELECT a[1] || a[i] AS foo,a[2] || a[5] AS bar -- assuming we have >= 5 rows for simplicity FROM ( SELECT array_agg(text_col ORDER BY text_col) AS a,count(*)::int4 AS i FROM tbl WHERE id between 10 AND 100 ) x 我如何用T-SQL最好地解决这个问题? ;WITH x AS ( SELECT row_number() OVER (ORDER BY name) AS rn,name AS a FROM #t WHERE id between 10 AND 100 ),i AS ( SELECT count(*) AS i FROM x ) SELECT (SELECT a FROM x WHERE rn = 1) + (SELECT a FROM x WHERE rn = i) AS foo,(SELECT a FROM x WHERE rn = 2) + (SELECT a FROM x WHERE rn = 5) AS bar FROM i 测试设置: CREATE TABLE #t( id INT PRIMARY KEY,name NVARCHAR(100)) INSERT INTO #t VALUES (3,'John'),(5,'Mary'),(8,'Michael'),(13,'Steve'),(21,'Jack'),(34,'Pete'),(57,'Ami'),(88,'Bob') 有更简单的方法吗? 解决方法编辑1:我添加了另一个解决方案,显示如何在SQL Server上模拟ARRAY_AGG(最后一个答案).编辑2:对于解决方案编号4)我添加了第三种连接方法. 我不确定我是否理解你的问题. a)不使用SQL Server中的数组,而是使用表变量或XML. b)要连接字符串(在本例中),我将使用SELECT @var = @var Name FROM tbl语句或XML xqueries. c)基于CTE和多个子查询的解决方案(WITH cte AS()FROM SELECT(SELECT * FROM cte.rn = 1)()…)将生成大量扫描和逻辑读取. 解决方案: --Creating the "array" DECLARE @Array TABLE ( Idx INT PRIMARY KEY,Val NVARCHAR(100) NOT NULL ); WITH Base AS ( SELECT Val = t.name,Idx = ROW_NUMBER() OVER(ORDER BY t.name ASC) FROM #t t WHERE t.id between 10 AND 100 ) INSERT @Array (Idx,Val) SELECT b.Idx,b.Val FROM Base b; --Concatenating all names DECLARE @AllNames NVARCHAR(4000); --”Reset”/Init @AllNames SET @AllNames = ''; --String concatenation SELECT @AllNames = @AllNames + ',' + a.Val FROM @Array a; --Remove first char (',') SELECT @AllNames = STUFF(@AllNames,1,''); --The final result SELECT @AllNames [Concatenating all names - using a table variable]; /* Concatenating all names - using a table variable ------------------------------------------------ Ami,Bob,Jack,Pete,Steve */ --Concatenating Idx=2 and Idx=5 --”Reset” @AllNames value SET @AllNames = ''; --String concatenation SELECT @AllNames = @AllNames + ',' + a.Val FROM @Array a WHERE a.Idx IN (2,5) --or a.Idx IN (2,(SELECT COUNT(*) FROM @Array)) ORDER BY a.Idx ASC; --Remove first char (',''); --The final result SELECT @AllNames [Concatenating Idx=2 and Idx=5 - using a table variable]; /* Concatenating Idx=2 and Idx=5 - using a table variable ------------------------------------------------------ Bob,Steve */ 2)表变量PIVOT: --Concatenating a finite number of elements (names) SELECT pvt.[1] + ',' + pvt.[0] AS [PIVOT Concat_1_and_i(0)],pvt.[2] + ',' + pvt.[5] AS [PIVOT Concat_2_and_5],pvt.* FROM ( SELECT a.Idx,a.Val FROM @Array a WHERE a.Idx IN (1,2,5) UNION ALL SELECT 0,a.Val --The last element has Idx=0 FROM @Array a WHERE a.Idx = (SELECT COUNT(*) FROM @Array) ) src PIVOT (MAX(src.Val) FOR src.Idx IN ([1],[2],[5],[0])) pvt; /* PIVOT Concat_1_and_i(0) PIVOT Concat_2_and_5 ----------------------- -------------------- Ami,Steve Bob,Steve */ 3)XML XQuery: SET ANSI_WARNINGS ON; GO DECLARE @x XML; ;WITH Base AS ( SELECT Val = t.name,Idx = ROW_NUMBER() OVER(ORDER BY t.name ASC) FROM #t t WHERE t.id BETWEEN 10 AND 100 ) SELECT @x = ( SELECT b.Idx AS [@Idx],b.Val AS [text()] FROM Base b FOR XML PATH('Element'),ROOT('Array') ); /* @x content <Array> <Element Idx="1">Ami</Element> <Element Idx="2">Bob</Element> <Element Idx="3">Jack</Element> <Element Idx="4">Pete</Element> <Element Idx="5">Steve</Element> </Array> */ --Concatenating all names (the result is XML,so a cast is needed) DECLARE @r XML; --XML result SELECT @r=@x.query(' (: $e = array element :) for $e in (//Array/Element) return string($e) '); SELECT REPLACE(CONVERT(NVARCHAR(4000),@r),' ',',') AS [Concatenating all names - using XML]; /* Concatenating all names - using XML ----------------------------------- Ami,Steve */ --Concatenating Idx=1 and all names SELECT @r=@x.query(' (: $e = array element :) for $e in (//Array/Element[@Idx=1],//Array/Element) return string($e) '); SELECT REPLACE(CONVERT(NVARCHAR(4000),') AS [Concatenating Idx=1 and all names - using XML]; /* Concatenating Idx=1 and all names - using XML --------------------------------------------- Ami,Ami,Steve */ --Concatenating Idx=1 and i(last name) DECLARE @i INT; SELECT @r=@x.query(' (: $e = array element :) for $e in (//Array/Element[@Idx=1],//Array/Element[@Idx=count(//Array/Element)]) return string($e) '); SELECT REPLACE(CONVERT(NVARCHAR(4000),') AS [Concatenating Idx=1 and i(last name) - using XML]; /* Concatenating Idx=1 and i(last name) - using XML ------------------------------------------------ Ami,Steve */ --Concatenating Idx=2 and Idx=5 SELECT @r=@x.query(' (: $e = array element :) for $e in (//Array/Element[@Idx=2],//Array/Element[@Idx=5]) return string($e) '); SELECT REPLACE(CONVERT(NVARCHAR(4000),') AS [Concatenating Idx=2 and Idx=5 - using XML (method 1)]; /* Concatenating Idx=2 and Idx=5 - using XML (method 1) ---------------------------------------------------- Bob,Steve */ --Concatenating Idx=2 and Idx=5 SELECT @x.value('(//Array/Element)[@Idx=2][1]','NVARCHAR(100)') + ',' + @x.value('(//Array/Element)[@Idx=5][1]','NVARCHAR(100)') AS [Concatenating Idx=2 and Idx=5 - using XML (method 2)];; /* Concatenating Idx=2 and Idx=5 - using XML (method 2) ---------------------------------------------------- Bob,Steve */ 4)如果问题是如何在SQL Server上模拟ARRAY_AGG,那么一个答案可能是:使用XML. SET ANSI_WARNINGS ON; GO DECLARE @Test TABLE ( Id INT PRIMARY KEY,GroupID INT NOT NULL,Name NVARCHAR(100) NOT NULL ); INSERT INTO @Test (Id,GroupID,Name) VALUES (3,'Bob'); WITH BaseQuery AS ( SELECT a.GroupID,a.Name FROM @Test a WHERE a.Id BETWEEN 10 AND 100 ) SELECT x.*,CONVERT(XML,x.SQLServer_Array_Agg).query (' for $e in (//Array/Element[@Idx=1],//Array/Element[@Idx=count(//Array/Element)]) return string($e) ') AS [Concat Idx=1 and Idx=i (method 1)],x.SQLServer_Array_Agg).query(' let $a := string((//Array/Element[@Idx=1])[1]) let $b := string((//Array/Element[@Idx=count(//Array/Element)])[1]) let $c := concat($a,",$b) (: " is used as a string delimiter :) return $c ') AS [Concat Idx=1 and Idx=i (method 2)],x.SQLServer_Array_Agg).query (' for $e in (//Array/Element[@Idx=(1,count(//Array/Element))]) return string($e) ') AS [Concat Idx=1 and Idx=i (method 3)] FROM ( SELECT a.GroupID,(SELECT ROW_NUMBER() OVER(ORDER BY b.Name) AS [@Idx],b.Name AS [text()] FROM BaseQuery b WHERE a.GroupID = b.GroupID ORDER BY b.Name FOR XML PATH('Element'),ROOT('Array') ) AS SQLServer_Array_Agg FROM BaseQuery a GROUP BY a.GroupID ) x; 结果: GroupID SQLServer_Array_Agg Concat Idx=1 and Idx=i (method 1) Concat Idx=1 and Idx=i (method 2) Concat Idx=1 and Idx=i (method 3) ------- ---------------------------------------------------------------------------------------------------------- --------------------------------- --------------------------------- --------------------------------- 1 <Array><Element Idx="1">Jack</Element><Element Idx="2">Steve</Element></Array> Jack Steve Jack,Steve Jack Steve 2 <Array><Element Idx="1">Ami</Element><Element Idx="2">Bob</Element><Element Idx="3">Pete</Element></Array> Ami Pete Ami,Pete Ami Pete (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |