我是SQL Server新手并遇到问题
以下是我的基线情况:
表foo:
id | pid | val1 | val2 | val3
------------------------------
1 | 4721 | 1 | 2 | 3
2 | 25 | 4 | 5 | 6
3 | 4721 | 7 | 8 | 9
结果表:
pid | id_1 | val1_1 | val2_1 | val3_1 | id_2 | val1_2 | val2_2 | val3_2 | id_3 | val1_3 | val2_3 | val3_3
----------------------------------------------------
4721 | 1 | 1 | 2 | 3 | 2 | 4 | 5 | 6 | 3 | 7 | 8 | 9
我想要的是选择所有匹配的行为pid = 4721,并在单独的列中显示它们。
答案 0 :(得分:2)
严格来说,这个问题的SQL答案是,"这是一个显示问题。显示是一个应用程序问题,而不是数据库问题。"从关系角度来说,这也要求服务器打破First Normal Form并创建重复组,这意味着它几乎肯定需要跳过几个圈,并且会有很大的局限性。
"正确的方式"根据DBA的说法,可能会这样做:
SELECT pid, id, val1, val2, val3
FROM Table
ORDER BY pid, id;
然后,在您的应用程序中,浏览结果集并根据需要格式化输出。
您甚至可以在id
中为每个pid
添加订单,以使其更轻松一些:
SELECT pid,
id,
val1,
val2,
val3,
ROW_NUMBER() OVER (PARTITION BY pid, ORDER BY id) AS "id_order"
FROM Table
ORDER BY pid, id;
但是,我们说你做不到。
如果您绝对 使用SQL执行此操作(例如,您的报告软件无法处理此类事情,并且您已获得)并且你知道每个id
你永远不会超过3 pid
,你可以尝试这样的事情:
;WITH Table_id_ordered AS (
SELECT pid,
id,
val1,
val2,
val3,
ROW_NUMBER() OVER (PARTITION BY pid, ORDER BY id) AS "id_order"
FROM Table
)
SELECT t1.pid,
t1.id as id_1,
t1.val1 as val1_1,
t1.val2 as val2_1,
t1.val3 as val3_1,
t2.id as id_2,
t2.val1 as val1_2,
t2.val2 as val2_2,
t2.val3 as val3_2,
t3.id as id_3,
t3.val1 as val1_3,
t3.val2 as val2_3,
t3.val3 as val3_3
FROM Table_id_ordered t1
LEFT JOIN Table_id_ordered t2
ON t2.pid = t1.pid
AND t2.id_order = t1.id_order + 1
LEFT JOIN Table_id_ordered t3
ON t3.pid = t2.pid
AND t3.id_order = t2.id_order + 1
WHERE t1.id_order = 1;
显然,对于任何id
,最多只能有pid
个{}。如上所述,它也不会告诉你表格中id
是否会在第五或第五位。他们只是完全没有结果。我提到的第一种方法将始终返回所有数据,并且可以编写应用程序以便轻松处理。
可以为id
的任意数量的pid
创建动态解决方案,但这些解决方案要复杂得多。
答案 1 :(得分:0)
我首先取消隐藏数据以获取列和值列表,分配新列名,然后动态转动数据。这适用于任何值的组合。
注意:我略微更改了列名,因此他们可以正确排序。
IF OBJECT_ID('tempdb..#yourTable') IS NOT NULL
DROP TABLE #yourTable;
IF OBJECT_ID('tempdb..#UnpivotTable') IS NOT NULL
DROP TABLE #UnpivotTable;
SELECT * INTO #yourTable
FROM
(
SELECT 1,4721,1,2,3
UNION ALL
SELECT 2,25,4,5,6
UNION ALL
SELECT 3,4721,7,8,9
) AS bar(id,pID,val1,val2,val3);
DECLARE @cols VARCHAR(MAX);
SELECT pID,
--This is where I create the column names
CONCAT(ROW_NUMBER() OVER (PARTITION BY pID,col ORDER BY pID,id2),'_',col) NewColName,
val INTO #UnpivotTable
FROM
(
--I need ID2 for ROW_NUMBER() so the NewColNames are applied to the correct values
SELECT *,id as ID2
FROM #yourTable
) A
UNPIVOT
(
val FOR col IN(ID,val1,val2,val3)
) unpvt
--Puts columns in alphabetic order into @cols
SELECT @cols = COALESCE(@cols + ',','') + QUOTENAME(NewColName)
FROM #UnpivotTable
--Group by gets rid of any duplicate column names
GROUP BY NewColName
ORDER BY NewColName
EXEC
(
'SELECT *
FROM #UnpivotTable
PIVOT
(
MAX(val) FOR newColName IN (' + @cols + ')
) pvt
WHERE pID = 4721'
)
--Cleanup
IF OBJECT_ID('tempdb..#yourTable') IS NOT NULL
DROP TABLE #yourTable;
IF OBJECT_ID('tempdb..#UnpivotTable') IS NOT NULL
DROP TABLE #UnpivotTable;
结果:
pID 1_id 1_val1 1_val2 1_val3 2_id 2_val1 2_val2 2_val3
----------- ----------- ----------- ----------- ----------- ----------- ----------- ----------- -----------
4721 1 1 2 3 3 7 8 9