【问题标题】:dynamically add column names and add their values as a row sql server动态添加列名并将它们的值添加为行 sql server
【发布时间】:2017-03-28 15:37:23
【问题描述】:

我有一个表 table1,列名为 a、b、c、d、e、f。 现在的任务是获取每列的值,该值肯定是单行值,并将其插入到其他 table2 - columns(x, y, z) 中。所以我的查询是这样的:

 insert into table2 (x, y, z)
select a, '', '' from table1
union all
select b, '', '' from table1
union all
select c, '', '' from table1
union all
select d, '', '' from table1
union all
select e, '', '' from table1
.
.
.
union all
select f, '', '' from table1

现在,如果在 table1 中添加了一个新列,那么我必须在其中添加一个 select 语句。只是想避免这种情况,我怎样才能编写一个自动考虑所有列并使其更短的动态查询。

【问题讨论】:

    标签: sql sql-server dynamic


    【解决方案1】:

    似乎您正在寻找动态 EAV 结构(实体属性值)。现在最酷的部分是@YourTable 可以是任何查询

    Declare @YourTable table (ID int,Col1 varchar(25),Col2 varchar(25),Col3 varchar(25))
    Insert Into @YourTable values
     (1,'a','z','k')
    ,(2,'g','b','p')
    ,(3,'k','d','a')
    
    
    Select A.ID
          ,C.*
     From  @YourTable A
     Cross Apply (Select XMLData=cast((Select A.* for XML Raw) as xml)) B
     Cross Apply (
                    Select Attribute = attr.value('local-name(.)','varchar(100)')
                          ,Value     = attr.value('.','varchar(max)')              -- change datatype if necessary
                     From  B.XMLData.nodes('/row') as A(r)
                     Cross Apply A.r.nodes('./@*') AS B(attr)
                     Where attr.value('local-name(.)','varchar(100)') not in ('ID','OtherFieldsToExclude')  -- Field Names case sensitive
                 ) C
    

    返回

    ID      Attribute   Value
    1       Col1        a
    1       Col2        z
    1       Col3        k
    2       Col1        g
    2       Col2        b
    2       Col3        p
    3       Col1        k
    3       Col2        d
    3       Col3        a
    

    【讨论】:

    • 谢谢这解决了我的问题,列名和值都来了。但是我在理解这种方法时仍然摸不着头脑。
    • @AjayRawat Cross Apply 是一个非常强大的选项。第一个会将行转换为 XML。第二个交叉应用将采用该 XML 并取消透视结果,
    【解决方案2】:

    一个更简单的方法是使用cross apply

    insert into table2 (x, y, z)
        select v.x, '', ''
        from table1 t1 cross apply
             (values (t1.a), (t1.b), (t1.c), (t1.d), (t1.e), (t1.f)
             ) v(x);
    

    如果您想在向表中添加新列时插入新值,那么您可能需要一个 DDL 并且可能需要一个 DML 触发器。 DML 触发器是“标准”触发器。

    您可以在documentation 中阅读有关 DDL 触发器的信息。

    也就是说,我对鼓励添加新列和新表的数据库系统高度怀疑。可能有更好的方法来设计应用程序,例如,使用 EAV 数据模型提供更大的属性灵活性。

    【讨论】:

      【解决方案3】:

      试试这个

      insert into table2 
      select Tmp.id, tb1.* from table1 tb1,
      ((SELECT B.id FROM (SELECT [value] = CONVERT(XML ,'<v>' + REPLACE('a,b,c,d,e,f' , ',' , '</v><v>')+ '</v>')) A     
      OUTER APPLY 
      (SELECT  id = N.v.value('.' , 'varchar(100)') FROM A.[value].nodes('/v') N ( v )) B)) Tmp 
      

      【讨论】:

        【解决方案4】:

        如果我没看错的话,这似乎是使用的最佳时机 PIVOT.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2022-09-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-06-23
          相关资源
          最近更新 更多