SQL 服务器动态列创建
SQL Server dynamic columns creation
我有一个 table 列和值如下
如何在第二个表格列中获取结果,动态列名称为 - 首先是 "prgmg_product_id",其余列是 "source ID 1","source ID 2" , "source ID 3"
我有一点时间把它扔在一起。我知道围绕 SO 的偏好是使用动态枢轴。我不太关心 sql 服务器中的 PIVOT。我发现语法非常迟钝。我倾向于更喜欢交叉表查询(也称为条件聚合)。额外的好处是这种方法几乎总是比动态 PIVOT 稍微快一点。
您还必须认识到,此处 post 一半以上的代码都存在设置问题。将来你应该 post ddl 和像这样的可消费格式的样本数据。这让我们更容易提供帮助。
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
prgmg_product_id int,
source_id_other int
)
insert #Something (prgmg_product_id, source_id_other) values
(3310, 11478),
(3337, 10833),
(3354, 11466),
(4039, 4846),
(4039, 65454),
(4039, 65456)
declare @StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by prgmg_product_id order by source_id_other) as RowNum
from #Something
)
select prgmg_product_id';
declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by prgmg_product_id order by prgmg_product_id desc';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select @DynamicPortion = @DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then source_id_other end) as SourceID' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from #Something
group by prgmg_product_id
order by COUNT(*) desc
)
declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;
exec sp_executesql @SqlToExecute
要使用动态 SQL 实现此目的,以下内容会有所帮助:
CREATE TABLE #Prgmg (
prgmg_product_id INT
,source_id_other INT
);
INSERT #Prgmg (
prgmg_product_id
,source_id_other
)
VALUES (3310,11478)
,(3337,10833)
,(3354,11466)
,(4039,4846)
,(4039,65454)
,(4039,65456);
DECLARE @DYColumns NVARCHAR(1000)
,@DYSqlQuery NVARCHAR(4000);
-- CREATE THE COLUMNS REQUIRED
SET @DYColumns = STUFF((
SELECT DISTINCT ','
+ N'sourceID'
+ CAST(ROW_NUMBER() OVER (PARTITION BY prgmg_product_id ORDER BY prgmg_product_id, source_id_other) AS NVARCHAR(10))
FROM #Prgmg
FOR XML PATH('')
), 1, 1, '');
-- CREATE THE DYNAMIC SQL AND ADD IN THE CREATED COLUMNS
SET @DYSqlQuery = '
SELECT prgmg_product_id,'
+ @DYColumns
+ ' FROM (
SELECT prgmg_product_id
,CAST(N''sourceID'' + CAST(ROW_NUMBER() OVER (
PARTITION BY prgmg_product_id ORDER BY prgmg_product_id, source_id_other
) AS NVARCHAR(10)) AS NVARCHAR(100)) AS Col
,source_id_other
FROM #Prgmg S1
) X
PIVOT(MIN(source_id_other) FOR Col IN (' + @DYColumns + ')) P'
EXECUTE sp_executesql @DYSqlQuery;
虽然这确实为您提供了解决方案,但您应该花时间理解所使用的概念。比如Columns的创建需要使用ROW_NUMBER
and the how that maps to the use of the PIVOT
。
我有一个 table 列和值如下
如何在第二个表格列中获取结果,动态列名称为 - 首先是 "prgmg_product_id",其余列是 "source ID 1","source ID 2" , "source ID 3"
我有一点时间把它扔在一起。我知道围绕 SO 的偏好是使用动态枢轴。我不太关心 sql 服务器中的 PIVOT。我发现语法非常迟钝。我倾向于更喜欢交叉表查询(也称为条件聚合)。额外的好处是这种方法几乎总是比动态 PIVOT 稍微快一点。
您还必须认识到,此处 post 一半以上的代码都存在设置问题。将来你应该 post ddl 和像这样的可消费格式的样本数据。这让我们更容易提供帮助。
if OBJECT_ID('tempdb..#Something') is not null
drop table #Something
create table #Something
(
prgmg_product_id int,
source_id_other int
)
insert #Something (prgmg_product_id, source_id_other) values
(3310, 11478),
(3337, 10833),
(3354, 11466),
(4039, 4846),
(4039, 65454),
(4039, 65456)
declare @StaticPortion nvarchar(2000) =
'with OrderedResults as
(
select *, ROW_NUMBER() over(partition by prgmg_product_id order by source_id_other) as RowNum
from #Something
)
select prgmg_product_id';
declare @DynamicPortion nvarchar(max) = '';
declare @FinalStaticPortion nvarchar(2000) = ' from OrderedResults Group by prgmg_product_id order by prgmg_product_id desc';
with E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select @DynamicPortion = @DynamicPortion +
', MAX(Case when RowNum = ' + CAST(N as varchar(6)) + ' then source_id_other end) as SourceID' + CAST(N as varchar(6)) + CHAR(10)
from cteTally t
where t.N <=
(
select top 1 Count(*)
from #Something
group by prgmg_product_id
order by COUNT(*) desc
)
declare @SqlToExecute nvarchar(max) = @StaticPortion + @DynamicPortion + @FinalStaticPortion;
exec sp_executesql @SqlToExecute
要使用动态 SQL 实现此目的,以下内容会有所帮助:
CREATE TABLE #Prgmg (
prgmg_product_id INT
,source_id_other INT
);
INSERT #Prgmg (
prgmg_product_id
,source_id_other
)
VALUES (3310,11478)
,(3337,10833)
,(3354,11466)
,(4039,4846)
,(4039,65454)
,(4039,65456);
DECLARE @DYColumns NVARCHAR(1000)
,@DYSqlQuery NVARCHAR(4000);
-- CREATE THE COLUMNS REQUIRED
SET @DYColumns = STUFF((
SELECT DISTINCT ','
+ N'sourceID'
+ CAST(ROW_NUMBER() OVER (PARTITION BY prgmg_product_id ORDER BY prgmg_product_id, source_id_other) AS NVARCHAR(10))
FROM #Prgmg
FOR XML PATH('')
), 1, 1, '');
-- CREATE THE DYNAMIC SQL AND ADD IN THE CREATED COLUMNS
SET @DYSqlQuery = '
SELECT prgmg_product_id,'
+ @DYColumns
+ ' FROM (
SELECT prgmg_product_id
,CAST(N''sourceID'' + CAST(ROW_NUMBER() OVER (
PARTITION BY prgmg_product_id ORDER BY prgmg_product_id, source_id_other
) AS NVARCHAR(10)) AS NVARCHAR(100)) AS Col
,source_id_other
FROM #Prgmg S1
) X
PIVOT(MIN(source_id_other) FOR Col IN (' + @DYColumns + ')) P'
EXECUTE sp_executesql @DYSqlQuery;
虽然这确实为您提供了解决方案,但您应该花时间理解所使用的概念。比如Columns的创建需要使用ROW_NUMBER
and the how that maps to the use of the PIVOT
。