When working with tabular data, you often need to group records based on one or more columns and merge the results into a single row with multiple columns. This is especially useful when dealing with multiple values associated with each group.
Suppose you have a table containing test results, where each row represents a specific test type and its corresponding result. For example, the "Results" table might have the following schema:
<code class="language-sql">CREATE TABLE Result( WorkOrder varchar(10), TestType varchar(20), Result decimal(10,2) );</code>
and the following data:
<code class="language-sql">INSERT INTO Result (WorkOrder, TestType, Result) VALUES ('HP19002316','VitaminA', 10.3), ('HP19002316','VitaminA', 11.3), ('HP19002316','VitaminA', 12.3), ('HP19002316','VitaminB', 13.4), ('HP19002316','VitaminB', 14.4), ('HP19002316','VitaminC', 15.5), ('HP19002316','VitaminD', 17.0)</code>
In order to group these results by "TestType" and create a new row with multiple columns for each result, we can use the "Crosstab" or "Pivot" operation. One approach is to use the "ROW_NUMBER" function to assign a sequence number to each result within the group and then use conditional aggregation to extract the required values.
<code class="language-sql">WITH RNs AS( SELECT WorkOrder, TestType, Result, ROW_NUMBER() OVER (PARTITION BY WorkOrder, TestType ORDER BY (SELECT NULL)) AS RN FROM dbo.Result) SELECT WorkOrder, TestType, MAX(CASE RN WHEN 1 THEN Result END) AS Result1, MAX(CASE RN WHEN 2 THEN Result END) AS Result2, MAX(CASE RN WHEN 3 THEN Result END) AS Result3 FROM RNs R GROUP BY WorkOrder, TestType;</code>
This query will produce the following output:
<code>WorkOrder TestType Result1 Result2 Result3 ========================================================== HP19002316 VitaminA 10.3 11.3 12.3 HP19002316 VitaminB 13.4 14.4 NULL HP19002316 VitaminC 15.5 NULL NULL HP19002316 VitaminD 17.0 NULL NULL</code>
However, this method is limited to a fixed number of results. To create a dynamic solution that can accommodate any number of results, we can use a technique called "cross-applied counting tables."
<code class="language-sql">DECLARE @SQL nvarchar(MAX), @CRLF nchar(2) = NCHAR(13) + NCHAR(10), @MaxTally int; SELECT @MaxTally = MAX(C) FROM (SELECT COUNT(*) AS C FROM dbo.Result GROUP BY WorkOrder, TestType) R; WITH N AS( SELECT N FROM (VALUES(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL),(NULL))N(N)), Tally AS( SELECT TOP (@MaxTally) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS I FROM N N1, N N2) SELECT @SQL = N'WITH RNs AS(' + @CRLF + N' SELECT WorkOrder,' + @CRLF + N' TestType,' + @CRLF + N' Result,' + @CRLF + N' ROW_NUMBER() OVER (PARTITION BY WorkOrder, TestType ORDER BY (SELECT NULL)) AS RN --ORDER BY 应为您的 ID/始终递增列' + @CRLF + N' FROM dbo.Result)' + @CRLF + N'SELECT WorkOrder,' + @CRLF + N' TestType,' + @CRLF + --由于不知道 SQL Server 版本,因此使用 FOR XML PATH STUFF((SELECT N',' + @CRLF + CONCAT(N' MAX(CASE RN WHEN ',T.I,N' THEN Result END) AS Result',T.I) FROM Tally T ORDER BY T.I ASC FOR XML PATH(N''),TYPE).value('(./text())[1]','nvarchar(MAX)'),1,3,N'') + @CRLF + N'FROM RNs R' + @CRLF + N'GROUP BY WorkOrder,' + @CRLF + N' TestType;'; PRINT @SQL; --您的好朋友。 EXEC sys.sp_executesql @SQL;</code>
This query uses a "count table" to create a sequence of integers that dynamically generates an SQL statement based on the maximum number of results in the table. This technique allows any number of results to be combined into a single row.
By using these methods, you can effectively group and merge tabular data into a more structured and meaningful format, simplifying data analysis and visualization.
The above is the detailed content of How to Dynamically Group and Merge Multiple Rows with Multiple Columns in SQL?. For more information, please follow other related articles on the PHP Chinese website!