【问题标题】:SQL Server 2008 ALTER TABLE add column with specific columnSQL Server 2008 ALTER TABLE 添加具有特定列的列
【发布时间】:2012-02-28 04:32:12
【问题描述】:

有什么方法可以在表格中添加一列,但我希望标题是日期,并且添加的每个新列都会有一个第二天的列标题,因此

SET @date1 = @date1 + 1

我希望表格看起来像这样,其中顶部的日期是脚本循环的每一天的新列:

StoreID StoreName     02/01/12    03/01/12    04/01/12
1234  Coles1         7512       8574        
1235  Coles2         7210       8441
1236  Coles3         4845       5448

当我运行脚本时,我收到以下错误消息:

消息 170,第 15 级,状态 1,第 1 行
第 1 行:“@Column”附近的语法不正确。
消息 170,第 15 级,状态 1,第 1 行
第 1 行:“@Column”附近的语法不正确。

这是我的脚本:

DECLARE @date datetime
DECLARE @date1 datetime
DECLARE @date2 datetime
DECLARE @Column varchar(8)
SET @date = '02 Jan 2012'
SET @date1 = '02 Jan 2012'
SET @date2 = '08 Jan 2012'
SET @Column = CONVERT(VARCHAR(8), @date1, 3)

IF NOT EXISTS (SELECT * FROM sysobjects WHERE xtype = 'U' AND name = '#vl_temp_trans') 
BEGIN
   CREATE TABLE #vl_temp_trans
      (StoreID INT,
       StoreName VARCHAR(100),
       @Column MONEY)                  ----> column name to be date "@Column)
END

WHILE (@date1 <= @date2)
BEGIN
   SET @Column =  CONVERT(VARCHAR(8), @date1, 3)

   ALTER table #vl_temp_trans
   ADD @Column MONEY     ----> column name to be date "@Column" 

   Insert into #vl_temp_trans (storeID, storeName, @Column)
      select storeId, storeName, TotalDailyTransactions
      from daily_trans t1 (nolock) 
      full outer join outlets t2 (nolock) on t1.StoreID = t2.StoreID 
      where DailyEnd = @date1 + 1

   SET @date1 = @date1 + 1
END 

【问题讨论】:

  • 你知道我为什么要修改你的问题吗?为什么要撤消它们?
  • 除了格式和可读性之外,哪个表有TotalDailyTransactionsDailyEnd 列?一个,两个?为什么您的任何列都没有以表别名为前缀以避免列名不明确错误(以及我们提出的问题)?
  • 检查更新的代码...可能会解决您的问题.....
  • 嗨 Aaron,感谢您的回复,但我没有撤消任何操作...
  • 在我应用正确的代码格式后,您对代码进行了两次编辑。我不会再麻烦了,但请突出显示错误消息、表格数据等,然后单击代码 {} 按钮,使它们看起来像您的代码示例。

标签: sql sql-server sql-server-2008 alter-table


【解决方案1】:

如果没有动态 SQL,您将无法做到这一点。这是一个查询,它将为您提供所需的结果。非常欢迎您取消注释 --INTO #t 位,但是目前还不清楚您想对 #temporary 表做什么(如果您告诉我们最终结果,而不是“我想将列名添加为 @列,也许我们也可以提供帮助)。为了继续引用该 #t 表,您需要继续使用同一范围内的代码 - 这意味着在同一 sp_executesql 调用中执行的更多动态 SQL。

DECLARE 
    @start DATE = '2012-01-02',
    @end   DATE = '2012-01-08';

DECLARE 
    @sql      NVARCHAR(MAX) = N'',
    @colMax   NVARCHAR(MAX) = N'',
    @colNames NVARCHAR(MAX) = N'';

;WITH x(rn) AS ( SELECT TOP (DATEDIFF(DAY, @start, @end) + 1) ROW_NUMBER()
  OVER (ORDER BY [object_id]) - 1 FROM sys.all_columns ), 
 y(d) AS ( SELECT CONVERT(CHAR(10), DATEADD(DAY, rn, @start)) FROM x 
)
SELECT @colMax += N',' + CHAR(13) + CHAR(10) 
     + QUOTENAME(d) + ' = SUM(CASE WHEN DailyEnd = ''' 
     + d + ''' THEN TotalDailyTransactions ELSE 0 END)',
    @colNames += N',' + QUOTENAME(d) FROM y;

SET @sql = 'SELECT StoreID, StoreName, ' + STUFF(@colNames, 1, 1, '')
    + ' --INTO #t 
        FROM ( SELECT StoreID, StoreName, ' + STUFF(@colMax, 1, 1, '')
    + ' FROM dbo.daily_trans
        WHERE DailyEnd >= ''' + CONVERT(CHAR(10), @start) + ''''
    + ' AND DailyEnd < ''' + CONVERT(CHAR(10), DATEADD(DAY, 1, @end)) + '''
        GROUP BY StoreID, StoreName
        UNION ALL SELECT StoreID, StoreName, ' + STUFF(@colMax, 1, 1, '')
    + ' FROM dbo.outlets
        WHERE DailyEnd >= ''' + CONVERT(CHAR(10), @start) + ''''
    + ' AND DailyEnd < ''' + CONVERT(CHAR(10), DATEADD(DAY, 1, @end)) + '''
        GROUP BY StoreID, StoreName) AS x';

PRINT @sql;
-- EXEC sp_executesql @sql;

【讨论】:

  • 嗨 Aaron,感谢您的帮助,但我收到以下错误消息:消息 139,级别 15,状态 1,行 2 无法为局部变量分配默认值。消息 170,级别 15,状态 1,第 2 行第 2 行:“MAX”附近的语法不正确。消息 170,级别 15,状态 1,第 2 行第 2 行:'(' 附近的语法不正确。消息 137,级别 15,状态 2,第 2 行必须声明变量 '@start'。消息 137,级别 15,状态 2,第 2 行必须声明变量“@colMax”。消息 137,级别 15,状态 2,第 2 行必须声明变量“@colNames”。消息 137,级别 15,状态 2,第 2 行必须声明变量“@sql” .
  • 我无法阅读评论中的所有垃圾内容,抱歉。您是否复制并粘贴了此代码示例并独立运行它,或者您是否对其进行了编辑或将其与其他一些脚本混合在一起?
  • 你能显示一个屏幕截图吗?因为我在这里运行它(针对 2008 R2 数据库和 2005 兼容模式的数据库)并且没有出现任何错误。您确定您使用的是 SQL Server 2008?
【解决方案2】:

我认为问题在于不能使用变量来定义列名。

我使用了您的一些代码进行测试。第一部分执行得很好。

DECLARE @date1 datetime
DECLARE @Column varchar(8)
SET @date1 = '02 Jan 2012'
SET @Column = CONVERT(VARCHAR(8), @date1, 3)
select @Column 

但是当我添加 CREATE TABLE 语句并一次执行所有语句时,我得到了与您相同的错误。

CREATE TABLE #vl_temp_trans
(StoreID INT,
StoreName VARCHAR(100),
@Column MONEY)                  ----> column name to be date "@Column)

为此,您需要将 CREATE TABLE 和 ALTER TABLE 语句构建为字符串,然后使用 EXECUTEsp_executesql 执行这些语句。 search for "dynamic sql" 也会给你一些描述这个的文章。

【讨论】:

    【解决方案3】:

    执行此代码需要做两件事...

    1. 利用SP_ExecuteSQl创建动态sql
    2. 您需要将您的临时表设为 Gobal,因为当您创建私有临时表时,它仅保留在 dynic sql sp 的范围内

    看看下面我更新的代码肯定会解决你的问题

    DECLARE @date datetime 
    DECLARE @date1 datetime 
    DECLARE @date2 datetime 
    DECLARE @ColumnNAAME varchar(8) 
    Declare @Query NVARCHAR(1000)
    DECLARE @ParmDefinition NVARCHAR(500);
    
    
    SET @date = getdate() 
    SET @date1 = getdate() 
    SET @date2 = getdate() 
    SET @ColumnNAAME = CONVERT(VARCHAR(8), @date1, 3)  
    IF NOT EXISTS (SELECT * FROM sysobjects WHERE xtype = 'U' AND name = '#vl_temp_trans')      
    BEGIN      
    SET @ParmDefinition = N'@Column varchar(8)';   
    Set @Query = 'CREATE TABLE ##vl_temp_trans  (StoreID INT,     StoreName VARCHAR(100),     ['+@ColumnNAAME+'] MONEY)' 
    
    EXECUTE sp_executesql  @Query,@ParmDefinition,
                          @Column = @ColumnNAAME;
    
                     ----> column name to be date "@Column)      
    SELECT * from  ##vl_temp_trans
    
    END 
    ELSE 
    BEGIN
        SELECT * from  ##vl_temp_trans
    END
    

    【讨论】:

    • 您好,感谢您的回复,但列名没有显示日期,而是显示@column。
    • 此外,我强烈建议不要使用 ##global 临时表,除非您真的想要 concurrency = 1(并且可以以某种方式强制执行)或者您不介意两个用户将他们的结果混合在一起。
    • @Sanjay,这个例子有什么作用?它为我所做的只是创建一个带有单个日期列的##global 临时表并返回一个空结果集。该表应包含以该范围内所有日期为轴的连接中的所有行 - 因此在这种情况下,#temp 表中应该有 9 列。
    • Asper 要求只需要创建##Global Temp 表。我只提供示例,您必须完成代码并执行。
    • 用户在哪里说他们需要##global 临时表?您了解#local 和##global 临时表之间的区别吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多