我的表格如下所示:
Member, Contract_Start, Contract_End
1, 1/1/2011, 12/30/2011
1, 1/1/2012, 12/30/2012
1, 1/1/2013, 12/30/2013
2, 7/1/2012, 12/30/2012
2, 1/1/2013, 12/30/2013
成员可以只有1份合同,合同数量没有上限。 我想将表格切换如下:
Member, Contract_Start1, Contract_End1, Contract_Start2, Contract_End2.....
1, 1/1/2011, 12/30/2011, 1/1/2012, 12/30/2012
2, 7/1/2012, 12/30/2012, 1/1/2013, 12/30/2013
感谢您提供任何帮助。
答案 0 :(得分:0)
我已经使用过这样的解决方案,并建议不要走这条路,因为这样的动态sql的维护/调试会长时间变硬。
您可以尝试演示Here
IF object_id('Test_Transpose') IS NOT NULL
DROP TABLE Test_Transpose
GO
CREATE TABLE Test_Transpose
(
memberID INT NOT NULL
,csdate datetime2(2) NULL
,cedate datetime2(2) NULL
)
INSERT INTO Test_Transpose (memberid,csdate,cedate)
SELECT 1,'1/1/2001','1/1/2001'
UNION ALL SELECT 1,'1/2/2001','1/2/2001'
UNION ALL SELECT 1,'1/3/2001','1/2/2001'
UNION ALL SELECT 1,'1/4/2001','1/2/2001'
UNION ALL SELECT 1,'1/5/2001','1/2/2001'
UNION ALL SELECT 2,'1/2/2001','1/2/2001'
UNION ALL SELECT 2,'1/3/2001','1/3/2001'
UNION ALL SELECT 3,'1/2/2001','1/2/2001'
UNION ALL SELECT 3,'1/3/2001','1/3/2001'
UNION ALL SELECT 3,'1/4/2001','1/4/2001'
UNION ALL SELECT 4,'1/2/2001','1/2/2001'
DECLARE @SQL NVARCHAR(MAX)=''
,@Startdate_SelectColumnList NVARCHAR(MAX)=''
,@EndDate_SelectColumnList NVARCHAR(MAX)=''
,@Final_SelectColumnList NVARCHAR(MAX)=''
,@PivotINColumnList NVARCHAR(MAX)=''
,@MaxContractDateCount INT=1
SELECT TOP 1 @MaxContractDateCount = COUNT(1)
FROM Test_Transpose
GROUP BY memberid
ORDER BY COUNT(1) desc
WHILE @MaxContractDateCount > 0
BEGIN
SELECT @Startdate_SelectColumnList = N'['+CAST(@MaxContractDateCount AS sysname)+N'] AS '
+N'StartDate'+CAST(@MaxContractDateCount AS sysname)
+CASE WHEN @Startdate_SelectColumnList=N'' THEN N'' ELSE N',' END
+@Startdate_SelectColumnList
SELECT @Enddate_SelectColumnList = N'['+CAST(@MaxContractDateCount AS sysname)+N'] AS '
+N'EndDate'+CAST(@MaxContractDateCount AS sysname)
+CASE WHEN @Enddate_SelectColumnList=N'' THEN N'' ELSE N',' END
+@Enddate_SelectColumnList
SELECT @Final_SelectColumnList = N'StartDate'+CAST(@MaxContractDateCount AS sysname)+N','
+N'EndDate'+CAST(@MaxContractDateCount AS sysname)
+CASE WHEN @Final_SelectColumnList=N'' THEN N'' ELSE N',' END
+@Final_SelectColumnList
SELECT @PivotINColumnList = N'['+CAST(@MaxContractDateCount AS sysname)+N']'
+CASE WHEN @PivotINColumnList=N'' THEN N'' ELSE N',' END
+@PivotINColumnList
SET @MaxContractDateCount=@MaxContractDateCount-1
END
--debug stmt
--SELECT @Startdate_SelectColumnList,@Enddate_SelectColumnList,@Final_SelectColumnList,@PivotINColumnList
SET @SQL = N'
SELECT q1.memberid,'
+@Final_SelectColumnList
+N'
FROM
(
SELECT memberid,'
+@Startdate_SelectColumnList
+N'
FROM
(
SELECT memberid,csdate,ROW_NUMBER() OVER (PARTITION BY memberid ORDER BY memberid,csdate) rowid
FROM test_transpose
)q
PIVOT
(MAX(csdate) FOR rowid IN ('+@PivotINColumnList+N'))pvt
)q1
JOIN
(
SELECT memberid,'
+@Enddate_SelectColumnList
+N'
FROM
(
SELECT memberid,cedate,ROW_NUMBER() OVER (PARTITION BY memberid ORDER BY memberid,csdate) rowid
FROM test_transpose
)q
PIVOT
(MAX(cedate) FOR rowid IN ('+@PivotINColumnList+N'))pvt
)q2
ON q1.memberid = q2.memberid
'
PRINT @SQL
EXECUTE sp_executesql @SQL
答案 1 :(得分:0)
我有一个版本的Postgres db明智地完成这项工作。这是我的代码示例。
DROP TABLE IF EXISTS x;
CREATE TABLE x ( member NUMERIC , contract_start DATE, contract_end DATE);
INSERT INTO x VALUES( 1, '1/1/2011', '12/30/2011' )
,( 1, '1/1/2012', '12/30/2012' )
,( 1, '1/1/2013', '12/30/2013' )
,( 2, '7/1/2012', '12/30/2012' )
,( 2, '1/1/2013', '12/30/2013' )
,( 3, '1/1/2012', '12/30/2012' )
,( 3, '1/1/2013', '12/30/2013' )
,( 3, '8/1/2013', '12/30/2013' )
,( 3, '8/1/2013', '12/30/2013' );
-- CREATE LANGUAGE 'plpgsql';
-- DROP SEQUENCE IF EXISTS seq;
-- CREATE SEQUENCE seq;
CREATE OR REPLACE FUNCTION make_table() RETURNS void AS
$BODY$
DECLARE
i RECORD;
colcnt INTEGER;
BEGIN
DROP TABLE IF EXISTS tmptable;
SELECT max(count) INTO colcnt FROM (SELECT count(*) FROM x GROUP BY member) a;
EXECUTE 'CREATE TABLE tmptable (member integer ,' ||
(SELECT array_to_string(array_agg(x1.col1 || ' date, ' || x1.col2 || ' date'), ', ')
FROM (SELECT 'contract_start' || col col1
, 'contract_end'|| col col2 FROM generate_series(1,colcnt) t(col) ) x1 ) || ')';
EXECUTE 'INSERT INTO tmptable (member) SELECT DISTINCT member FROM x';
FOR i IN SELECT * FROM x ORDER BY member LOOP
PERFORM setval('seq',1);
EXECUTE 'UPDATE tmptable SET ' || x1.col
FROM (SELECT array_to_string(array_agg(' contract_start'
|| nextval('seq')-1 || ' = ''' || i.contract_start || ''', contract_end'
|| currval('seq')-1 || ' = ''' || i.contract_end ), ''', ') || ''' WHERE member = ' || member || ';' col
FROM x WHERE member = i.member GROUP BY member) x1;
END LOOP;
END;
$BODY$ LANGUAGE plpgsql;
SELECT * FROM make_table();
SELECT * FROM tmptable;
这是我第一次回答。希望这是相关的。 (请只运行一次评论)。
此外,每次插入,更新或删除时调用函数的过程都可以通过触发器自动执行。以下代码将替换上面的代码。
-- following commented lines for first time run :
-- CREATE LANGUAGE 'plpgsql';
-- DROP SEQUENCE IF EXISTS seq;
-- CREATE SEQUENCE seq;
-- DROP FUNCTION IF EXISTS make_table();
CREATE OR REPLACE FUNCTION make_table() RETURNS TRIGGER AS
$BODY$
DECLARE
i RECORD;
colcnt INTEGER;
BEGIN
DROP TABLE IF EXISTS tmptable;
SELECT max(count) INTO colcnt FROM (SELECT count(*) FROM x GROUP BY member) a;
EXECUTE 'CREATE TABLE tmptable (member integer ,' ||
(SELECT array_to_string(array_agg(x1.col1 || ' date, ' || x1.col2 || ' date'), ', ')
FROM (SELECT 'contract_start' || col col1
, 'contract_end'|| col col2 FROM generate_series(1,colcnt) t(col) ) x1 ) || ')';
EXECUTE 'INSERT INTO tmptable (member) SELECT DISTINCT member FROM x';
FOR i IN SELECT * FROM x ORDER BY member LOOP
PERFORM setval('seq',1);
EXECUTE 'UPDATE tmptable SET ' || x1.col
FROM (SELECT array_to_string(array_agg(' contract_start'
|| nextval('seq')-1 || ' = ''' || i.contract_start || ''', contract_end'
|| currval('seq')-1 || ' = ''' || i.contract_end ), ''', ') || ''' WHERE member = ' || member || ';' col
FROM x WHERE member = i.member GROUP BY member) x1;
END LOOP;
RETURN new;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER create_tmptable AFTER INSERT OR UPDATE OR DELETE OR TRUNCATE
ON x FOR STATEMENT EXECUTE PROCEDURE make_table();
-- For Test insert:
INSERT INTO x VALUES( 4, '1/1/2011', '12/30/2011' );
SELECT * FROM tmptable;