【问题标题】:Dynamically add columns to temp table based on rows in another temp table根据另一个临时表中的行向临时表动态添加列
【发布时间】:2017-01-23 15:28:33
【问题描述】:

我正在尝试根据另一个临时表的行数构建一个具有动态列数的临时表。假设我在#table1 中有 89 行,在 #table2 我想使用行数并将相应的行值作为列名。我一直在摆弄这个,但我不断收到错误。这是我的查询,稍后将转换为 proc。

我的表看起来像这样(所有列都是 varchar,如果导入的日期没有该 CVE 编号的数据,则允许为空 - CVEId 与 CVENumber 表上的 FK 约束 CVEID 相关):

CVEId     D20160901     D20160902     D20160903     D20160904     D20160905
1         6182          6473          5879          NULL          NULL
2         72862         76583         NULL          NULL          74772

CVENumber Table:
CVEID     CVENumber
1         CVE-781-2016
2         CVE-006-2016

我希望获取列的日期,或者可能使用注入的日期作为第一行 - 对此数据运行查询,我可以指定 09-01-2016 到 09-03-2016。并从表中返回具有 CVENumber 表中引用的 CVENumber 的所有行。我希望我的结果如下所示:

CVE Number     09-01-2016     09-02-2016     09-03-2016
CVE-781-2016         6182           6473           8579
CVE-006-2016        72682          76583              0

我希望这能澄清我正在尝试做的事情。

我当前使用 STUFF() 的查询从 #FixedDates 中获取行并将其转换为列。我想将返回到@cols 的那些列作为列添加到#query_results

Set nocount on

Insert #tmp
EXEC sp_columns @table_name = N'CVECountsByDate'

-- Using collate to force the DB to only look at Uppercase values
DECLARE @cols varchar(max), @query varchar(max), @cols2 varchar(MAX)

INSERT #FixedDays
SELECT Replace(COLUMN_NAME, 'D' collate Latin1_General_CS_AS, '' collate Latin1_General_CS_AS) from #Tmp 
WHERE COLUMN_NAME LIKE 'D%' collate Latin1_General_CS_AS OR COLUMN_NAME = 'CVEId' ORDER BY COLUMN_NAME DESC


SET @cols = STUFF((SELECT ',' + QUOTENAME(QT.COLUMN_NAME) + ' varchar(100)'
                 FROM #FixedDays QT
                 GROUP BY QT.COLUMN_NAME
                 ORDER BY QT.COLUMN_NAME
                 FOR XML PATH(''), TYPE
                 ).value('.', 'VARCHAR(MAX)')
                 ,1,1,'')

SET @cols2 = N'CREATE TABLE #query_results (' + @cols + ') '
--EXEC(@cols2)
SELECT @cols2

DROP TABLE #FixedDays
DROP TABLE #Tmp

【问题讨论】:

  • 您为什么不希望它们成为行而不是新列?对于您需要对这些数据执行的任何其他操作,使用归一化的数据要容易得多。
  • 这些列的格式 [不是我的设计] 类似于日期格式,但如下所示:列名称中的 2016 年 9 月 1 日为 D20160901。我正在尝试使用该列名并将其转换为 09-01-2016。存储过程用于创建报告。我正在寻找以正确格式创建日期的临时表,并为开始日期和结束日期传递两个参数。
  • 这听起来像动态数据透视表或动态交叉表比尝试像这样调整临时表更好。
  • 你知道我该怎么做吗?我对数据透视表不太强。 PIVOT 表能否将结果返回给我的报表查询?
  • 这将是您报告的查询。这是一个很好的例子。 stackoverflow.com/questions/10404348/…

标签: sql-server temp-tables dynamicquery


【解决方案1】:

这就是我最终做的......

CREATE TABLE #Tmp
(TABLE_QUALIFIER varchar(40),
  TABLE_OWNER varchar(20),
  TABLE_NAME varchar(40),
  COLUMN_NAME varchar(40),
  DATA_TYPE int,
  TYPE_NAME varchar(20),
  PREC int, LENGTH int,
  SCALE int, RADIX int,
  NULLABLE char(4),
  REMARKS varchar(128),
  COLUMN_DEF varchar(40),
  SQL_DATA_TYPE int,
  SQL_DATETIME_SUB int,
  CHAR_OCTET_LENGTH int,
  ORDINAL_POSITION int,
  IS_NULLABLE char(4),
  SS_DATA_TYPE int)
CREATE TABLE #FixedDays  
 (COLUMN_NAME varchar(40))
CREATE TABLE #query_results
(CVENumber varchar(100) null)
Set nocount on
Insert #tmp
EXEC sp_columns @table_name = N'CVECountsByDate'
INSERT #FixedDays
SELECT Replace(COLUMN_NAME, 'D' collate Latin1_General_CS_AS, '' collate Latin1_General_CS_AS) from #Tmp 
WHERE COLUMN_NAME LIKE 'D%' collate Latin1_General_CS_AS OR COLUMN_NAME = 'CVEId'
DECLARE @listStr VARCHAR(MAX)
DECLARE @FixedList VARCHAR(MAX)
SELECT @FixedList = COALESCE(@FixedList,'[') + COLUMN_NAME + '] VARCHAR(MAX) NULL, [' FROM #FixedDays
SELECT @FixedList = substring(@FixedList, 1, len(@FixedList) -1)
SET @FixedList = LEFT(@FixedList, len(@FixedList)-1) -- Altered Column List
EXEC(N'ALTER TABLE #query_results ADD ' + @FixedList + '')
INSERT INTO #query_results 
SELECT CVEDetails.CVENumber, CVECountsByDate.* FROM CVECountsByDate INNER JOIN CVEDetails ON  CVECountsByDate.CVEId = CVEDetails.CVEID
ALTER TABLE #query_results DROP column CVEId

DROP TABLE #query_results
DROP TABLE #Tmp
DROP TABLE #FixedDays

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多