【问题标题】:View - select all fields of two tables when both tables have an identical column name查看 - 当两个表具有相同的列名时,选择两个表的所有字段
【发布时间】:2021-03-01 09:13:35
【问题描述】:

我想创建一个选择 2 个表的所有列的视图。我必须选择所有列(我不能写列名,因为可以添加列)。

我的问题是两个表都有同名的列。而且我无法更改列名。

CREATE OR ALTER VIEW [dbo].[vwSomething]
AS
    SELECT         
        dbo.A.*,
        dbo.B.*
    FROM            
        dbo.A
    INNER JOIN      
        dbo.B ON dbo.A.AID = dbo.B.AID 
GO

【问题讨论】:

  • 谁在向基表添加列并且自己不能修改视图?也许设置一个定期刷新视图的代理作业?
  • 如果您使用SELECT * 创建视图,稍后添加到基础表的列将自动出现在视图中。请参阅stackoverflow.com/q/22716598/95 了解更多信息。
  • 我知道,我有一个运行EXECUTE sp_refreshview...的proc
  • 您的问题是什么?如何要求所有列名在数据库中的所有表中都是唯一的? DDL trigger 会让您劝阻使用冲突的列名。
  • @SMor 没有懒惰的借口! - 这是一个供多个客户使用的系统,每个客户都可以在表格中添加他想要的列。

标签: sql sql-server tsql sql-view


【解决方案1】:

您必须为视图列命名:

CREATE OR ALTER VIEW [dbo].[vwSomething] (c1, c2, c3, ...)
AS
SELECT         dbo.A.*,
               dbo.B.*
FROM            dbo.A
INNER JOIN      dbo.B ON dbo.A.AID = dbo.B.AID 
GO

或者

CREATE OR ALTER VIEW [dbo].[vwSomething]
AS
SELECT         dbo.A.col1 c1, dbo.A.col2 c2, ...
               dbo.B.cola ca, dbo.B.colb cb, ... 
FROM            dbo.A
INNER JOIN      dbo.B ON dbo.A.AID = dbo.B.AID 
GO

一个视图应该总是返回相同的列,即使后来有人将一列添加到它的一个基表中。

【讨论】:

    【解决方案2】:

    您需要列出列。如果重复的列名包含相同的数据,您可以使用此快捷方式获取列表:

    select string_agg(column_name, ', ') within group (order by table_name, ordinal_position)
    from (select c.*,
                 row_numbrer() over (partition by column_name order by table_name) as seqnum
          from information_schema.columns c
          where table_name in ('A', 'B') and table_schema = 'dbo'
         ) c
    where seqnum = 1;
    

    然后您可以将该列表复制到您的查询中。

    【讨论】:

      【解决方案3】:

      好的!然后不要使用Select * 并枚举您的列并为它们分配别名

      SELECT a.Column1 as Alias1,b.Column1 as Alias2
      FROM            dbo.A a
      INNER JOIN      dbo.B b ON dbo.A.AID = dbo.B.AID 
      

      【讨论】:

        【解决方案4】:

        视图中的列名应该始终是唯一的。您可以为您的列分配一个别名,以将其与表 A 和表 B 区分开来。如果您担心将来添加新列,那么您可以使用如下动态 SQL。

        DROP TABLE IF EXISTS #TempColumDetails
        CREATE TABLE #TempColumDetails ([Id]INT IDENTITY(1,1), [ColumnName] VARCHAR(500),[ColumnAlias] VARCHAR(500),[TableAlias] VARCHAR(50))
        
        INSERT INTO #TempColumDetails
        SELECT
            COLUMN_NAME AS [ColumnName], 
            COLUMN_NAME+'_'+'T1' [ColumnAlias],
            'T1' AS [TableAlias]
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'A'
        ORDER BY ORDINAL_POSITION
        
        INSERT INTO #TempColumDetails
        SELECT
            COLUMN_NAME AS [ColumnName], 
            COLUMN_NAME+'_'+'T2' [ColumnAlias],
            'T2' AS [TableAlias]
        FROM INFORMATION_SCHEMA.COLUMNS
        WHERE TABLE_NAME = 'B'
        ORDER BY ORDINAL_POSITION
        
        
        DECLARE @MaxId INT,@Count INT
        SELECT @MaxId = MAX(Id) FROM #TempColumDetails
        
        DECLARE @TSQL NVARCHAR(MAX) 
        SET @TSQL = 'CREATE OR ALTER VIEW [dbo].[vwSomething]
        AS
        SELECT ';
        SET @Count = 1;
        WHILE(@Count<=@MaxId)
        BEGIN
            DECLARE @ColumnName VARCHAR(500),@ColumnAlias VARCHAR(500),@TableAlias VARCHAR(50)
            SELECT @ColumnName = ColumnName, @ColumnAlias = ColumnAlias, @TableAlias = TableAlias FROM #TempColumDetails WHERE Id = @Count  
            IF(@Count = @MaxId) 
            BEGIN 
                SELECT @TSQL = @TSQL+@TableAlias+'.'+@ColumnName+' AS '+@ColumnAlias+' '
            END
            ELSE
            BEGIN
                SELECT @TSQL = @TSQL+@TableAlias+'.'+@ColumnName+' AS '+@ColumnAlias+', '       
            END
            SET @Count = @Count + 1;
        END
        
        SELECT @TSQL = @TSQL + 'FROM  dbo.A T1
        JOIN      dbo.B T2 ON T1.AID = T2.AID ';
        
        EXEC(@TSQL)
        
        

        【讨论】:

        • 如果你需要一个游标,那么就使用一个游标。针对 MAX 值循环递增的 ID 只是更容易出错且速度较慢的游标版本。并停止应用该 模式,没有充分的理由。
        • 感谢您的 cmets,我认为游标比 while 循环更能影响性能。我在这里使用了临时表,因为在 CTE 或派生表中不允许使用 ORDER BY 子句,除非提到顶部的某些记录(例如 50)。
        猜你喜欢
        • 2012-05-26
        • 2020-01-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-12-23
        • 1970-01-01
        • 2021-04-11
        • 2019-02-10
        相关资源
        最近更新 更多