使用PIVOT做这个看似微不足道的任务应该是简单而明显的 - 但事实并非如此。
什么是最简洁的转换方式,不一定使用数据透视表,仅限于使用“纯”SQL(请参阅下面的其他因素)?
它不应该影响答案,但请注意,Python 3.X前端正用于在MS SQL Server 2012后端上运行SQL查询。
背景 :
我需要通过调用Python 3.x中的SQL代码来创建CSV文件。 CSV标题行是根据保存查询结果的SQL表的字段(列)名称创建的。 以下SQL代码提取字段名称并将它们返回为N行1列 - 但我需要它们作为N行的1行。 (在下面的例子中,最终结果必须是“A”,“B”,“C”。)
CREATE TABLE #MyTable -- ideally the real code uses "DECLARE @MyTable TABLE"
(
A varchar( 32 ),
B varchar( 32 ),
C varchar( 32 )
) ;
CREATE TABLE #MetaData -- ideally the real code uses "DECLARE @MetaData TABLE"
(
NameOfField varchar( 32 ) not NULL
) ;
INSERT INTO #MetaData
SELECT name
FROM tempdb.sys.columns as X
WHERE ( object_id = Object_id( 'tempdb..#MyTable' ) )
ORDER BY column_id ; -- generally redundant, ensures correct order if results returned in random order
/*
OK so far, the field names are returned as 3 rows of 1 column (entitled "NameOfField").
Pivoting them into 1 row of 3 columns should be something simple like:
*/
SELECT NameOfField
FROM #MetaData AS Source
PIVOT
(
COUNT( [ NameOfField ] ) FOR [ NameOfField ]
IN ( #MetaData ) -- I've tried "IN (SELECT NameOfField FROM #Metadata)"
) AS Destination ;
此错误会引发两次,一次是COUNT,一次是PIVOT语句的“FOR”子句:
Msg 207, Level 16, State 1, Line 32
Invalid column name ' NameOfField'.
如何使用#Metadata的内容让PIVOT工作?还是有另一种简单的方法吗?
其他背景因素需要注意:
更新:这个问题与SQL Server dynamic PIVOT query?略有不同。在我的情况下,我必须保留字段的顺序,这个问题不是必需的。
为什么我需要这样做:
简而言之:我们有很多网站,很多用户,很多查询。通过让SQL“动态创建”标题行,我们消除了必须手动管理/协调/推出SQL更改给所有受影响方的麻烦。
我不确定“纯粹的”sql是什么。你指的是ANSI-92 SQL吗?
无论如何,如果你可以使用SQL变量,试试这个:
DECLARE @STRING VARCHAR(MAX)
SELECT @STRING = COALESCE(@STRING + ', ' + '"' + NameOfField + '"', '"' + NameOfField + '"')
FROM #MetaData
SELECT @STRING
/*
Results:
"A", "B", "C"
*/
致@Tab Alleman,谢谢。我能够修改SQL Server dynamic PIVOT query?的答案,以满足我所有需求的方式进行交换(见下文)。
注意:由于某种原因,“DISTINCT”关键字按字母顺序放置字段 - 这是我不想要的。 评论该单词(如下所述)保留了字段的顺序。我对这样做有点不安,但在这种情况下它应该是安全的,因为选择#MetaData的值保证是唯一的。 通过在#MyTable中交换字段A和B并取消注释“DISTINCT”关键字,可以很容易地看出差异
--drop table #MyTable
--drop table #MetaData
Create TABLE #MyTable
(
A varchar( 10 ),
B varchar( 10 ),
C varchar( 10 )
)
;
CREATE TABLE #MetaData
(
NameOfField varchar( 100 ) not NULL,
Position int
)
;
INSERT INTO #MetaData
SELECT name, column_id
FROM tempdb.sys.columns as X
WHERE ( object_id = Object_id( 'tempdb..#MyTable' ) )
--ORDER BY column_id -- normally redundant, guards against results being returned in random order
;
select * from #MetaData
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX);
SET @cols = STUFF( (SELECT
-- DISTINCT
',' + QUOTENAME( c.NameOfField )
FROM #MetaData AS c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
--print( @cols )
set @query = 'SELECT ' + @cols + ' from
(
select NameOfField
from #MetaData
) AS x
pivot
(
MAX( NameOfField )
for NameOfField in ( '+ @cols + ' )
) AS p
'
--print( @query )
execute( @query )
drop table #MyTable
drop table #MetaData