【问题标题】:Create a table from a Select query从 Select 查询创建表
【发布时间】:2019-08-25 07:55:48
【问题描述】:

我有一个查询,它在 SQL Server 2008 R2 Express 中连接 7 个表,总共 852 列。 我正在尝试使用该查询的输出创建一个新表

尝试使用 INTO,但由于表中的某些列具有重复名称,因此无法正常工作

USE VistaBI
SELECT *
INTO NewTable
FROM         dbo.Agente FULL JOIN
                      dbo.Cte ON dbo.Agente.Agente = dbo.Cte.Agente 
                      FULL JOIN
                      dbo.CteEnviarA ON dbo.Agente.Agente = dbo.CteEnviarA.Agente 
                      FULL JOIN
                      dbo.Unidad ON dbo.CteEnviarA.Unidad = dbo.Unidad.Unidad 
                      FULL JOIN
                      dbo.Venta ON dbo.Agente.Agente = dbo.Venta.Agente 
                      FULL JOIN
                      dbo.VentaD ON dbo.Agente.Agente = dbo.VentaD.Agente 
                      FULL JOIN
                      dbo.Art ON dbo.VentaD.Articulo = dbo.Art.Articulo
                      FULL JOIN 
                      dbo.Alm ON dbo.Venta.Almacen = dbo.Alm.Almacen

有没有一种方法可以自动创建表,而不必为 852 列中的每一列键入唯一的名称和数据类型?

【问题讨论】:

  • 重复列名的期望结果是什么?结果表中的列名必须是唯一的,那么当它们重复时,您希望它们是什么?您可能可以使用动态 sql 做一些事情。不过,我敢打赌,您可以更有效地利用您的时间来思考为什么需要一个包含 852 列的表,以及是否可能没有更好的方法来实现这一最终目标。
  • 嗨,Tab,我不太关心列名,我会将所有这些信息导入 BI 工具,所以我需要 852 列。
  • 您能否更具体地了解“导入 BI 工具”的含义?也许您创建了一个视图而不是一个新表?与其他解决方案相比,您认为需要创建此表的原因是什么?
  • 嗨Tab,这个完整的范围是我们必须将这个新表发布到Azure,整个数据库有1043个表,我只需要提到的这7个表的信息。此表将在 Azure 中发布,然后连接到 PowerBI 以进行所需的分析
  • 为什么不在 Azure 中发布各个表,并编写一个视图或存储过程来执行此操作? PowerBI 可以使用视图或过程。

标签: sql sql-server tsql sql-server-2008 sql-server-2008-r2


【解决方案1】:

我是动态做的,试试这个代码:列名将变成表名+列名,所以不会重复列名。

DECLARE @strColumns varchar(max) = ''

SELECT @strColumns = COALESCE(@strColumns + ',', '') + A.TableName + '.' + QuoteName(Column_Name) + ' AS ' + A.Alies
FROM (
SELECT Column_Name, 'Agente' TableName, 'Agente_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'Agente' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'Cte' TableName, 'Cte_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'Cte' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'CteEnviarA' TableName, 'CteEnviarA_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'CteEnviarA' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'Unidad' TableName, 'Unidad_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'Unidad' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'Venta' TableName, 'Venta_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'Venta' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'VentaD' TableName, 'VentaD_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'VentaD' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'Art' TableName, 'Art_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'Art' AND DATA_TYPE != 'timestamp'
UNION ALL
SELECT Column_Name, 'Alm' TableName, 'Alm_' + QuoteName(Column_Name) AS Alies FROM INFORMATION_SCHEMA.COLUMNS WHERE Table_Name = 'Alm' AND DATA_TYPE != 'timestamp'
) AS A

SELECT @strColumns =SUBSTRING(@strColumns,2, len(@strColumns) - 1)
SELECT @strColumns


EXEC( 'SELECT 
    '+ @strColumns +' INTO ##temp
    FROM dbo.Agente 
    FULL JOIN dbo.Cte ON dbo.Agente.Agente = dbo.Cte.Agente 
    FULL JOIN dbo.CteEnviarA ON dbo.Agente.Agente = dbo.CteEnviarA.Agente 
    FULL JOIN dbo.Unidad ON dbo.CteEnviarA.Unidad = dbo.Unidad.Unidad 
    FULL JOIN dbo.Venta ON dbo.Agente.Agente = dbo.Venta.Agente 
    FULL JOIN dbo.VentaD ON dbo.Agente.Agente = dbo.VentaD.Agente 
    FULL JOIN dbo.Art ON dbo.VentaD.Articulo = dbo.Art.Articulo
    FULL JOIN dbo.Alm ON dbo.Venta.Almacen = dbo.Alm.Almacen')

SELECT * FROM ##temp
DROP TABLE ##temp

【讨论】:

  • 感谢 Hasan,不幸的是,当我尝试您的解决方案时,我收到一条错误消息,指出表只能有一个时间戳类型列,不确定它是否与您的代码或表结构有关
  • 我可以帮你,让我更新我的代码,有多个时间戳列,我们需要排除它
  • @rzbartali 代码已更新,立即尝试,如果您遇到任何其他错误,请告诉我
  • 提示:将对象名称组装成动态 SQL 语句时的最佳做法是使用 QuoteName() 以避免出现奇怪名称的问题,例如New Table 带有空格或保留字,例如 From
  • 您可能不想将QuoteName 应用于列名的一部分,例如'Agente_' + QuoteName(Column_Name) 然后使用A.TableName + '.' + QuoteName(Column_Name) 重复该过程。
【解决方案2】:

明确选择列名而不是使用 *

下面我用两张表举例

select 
    a.person_id,
    a.city,
    city.city_id
into 
    mytable 
from 
    table1 a
inner join 
    city on a.city = city.city

在你的情况下

SELECT table_name.col1,table_nae.col2..... use explicitly column name in selection
INTO NewTable
FROM         dbo.Agente FULL JOIN
                      dbo.Cte ON dbo.Agente.Agente = dbo.Cte.Agente 
                      FULL JOIN
                      dbo.CteEnviarA ON dbo.Agente.Agente = dbo.CteEnviarA.Agente 
                      FULL JOIN
                      dbo.Unidad ON dbo.CteEnviarA.Unidad = dbo.Unidad.Unidad 
                      FULL JOIN
                      dbo.Venta ON dbo.Agente.Agente = dbo.Venta.Agente 
                      FULL JOIN
                      dbo.VentaD ON dbo.Agente.Agente = dbo.VentaD.Agente 
                      FULL JOIN
                      dbo.Art ON dbo.VentaD.Articulo = dbo.Art.Articulo
                      FULL JOIN 
                      dbo.Alm ON dbo.Venta.Almacen = dbo.Alm.Almacen

【讨论】:

  • 如果有 100 列要获取怎么办?如前所述.. 852
  • @Rhythm 使用 table_name.columname 写入 100 列名称
  • 是的,我知道这个解决方案,我想知道是否有一些不同的类型函数可以自动提取唯一列而不是显式地写入每个列名.. 我想没有
  • 这并没有试图回答这个问题:“有没有一种方法可以自动创建表,而不必为 852 列中的每一列键入唯一的名称和数据类型?”
【解决方案3】:

您可以做的是首先创建一个表,然后使用动态更改语句添加您需要的列数,例如:

CREATE TABLE MYTABLE 
(
A INT,
B INT
)


DECLARE @I INT = 1, @COLNAME VARCHAR(20),@SQL VARCHAR(MAX)
WHILE (@I < 852)
BEGIN
SET @COLNAME = CAST(@I AS VARCHAR(20))


SET @SQL ='
ALTER TABLE MYTABLE
ADD [' + @COLNAME + '] VARCHAR(MAX);'
PRINT @SQL
EXEC(@SQL)
SET @I = @I + 1

END

然后只需将插入语句更改为:

INSERT INTO mytable
SELECT *
FROM   dbo.agente
       FULL JOIN dbo.cte
              ON dbo.agente.agente = dbo.cte.agente
       FULL JOIN dbo.cteenviara
              ON dbo.agente.agente = dbo.cteenviara.agente
       FULL JOIN dbo.unidad
              ON dbo.cteenviara.unidad = dbo.unidad.unidad
       FULL JOIN dbo.venta
              ON dbo.agente.agente = dbo.venta.agente
       FULL JOIN dbo.ventad
              ON dbo.agente.agente = dbo.ventad.agente
       FULL JOIN dbo.art
              ON dbo.ventad.articulo = dbo.art.articulo
       FULL JOIN dbo.alm
              ON dbo.venta.almacen = dbo.alm.almacen  

这将为您提供列名称为 1、2、3.... 等的结果,但它是一个动态名称,可让您不必手动命名列。

【讨论】:

  • 谢谢,但不幸的是,我需要一个半描述性的名称,因为这将用于 BI 工具
  • @rzbartali 那么为什么您对我对您的问题的评论的回复说“我不太关心列名”?当你不断改变问题时,人们很难帮助你。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-08
  • 2012-08-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
相关资源
最近更新 更多