如何选择*但没有“列名在每个视图中必须唯一”

时间:2011-06-21 10:15:41

标签: sql-server tsql select view

我需要封装一组我们在供应商的数据库服务器上频繁使用的表JOIN。我们在提取物等的许多地方重复使用相同的JOIN逻辑。似乎VIEW允许在一个地方定义和维护JOIN。

CREATE VIEW MasterView
AS
SELECT *
FROM entity_1 e1
INNER JOIN entity_2 e2 ON e2.parent_id = entity_1.id
INNER JOIN entity_3 e3 ON e3.parent_id = entity_2.id
/* other joins including business logic */
etc.

问题是供应商定期更改数据库(列添加,名称更改),我希望它自动反映在“MasterView”中。

SELECT *会允许这样,但基础表都有ID列,所以我得到“每个视图中的列名必须是唯一的”错误。

我特别想避免列出表中的列名,因为a)它需要经常维护b)每个表有几百列。

有没有办法实现SELECT *的动态,但有效地排除了某些列(即ID列)

由于

6 个答案:

答案 0 :(得分:5)

  

我特别想避免列出表中的列名,因为a)它需要经常维护b)每个表有几百列。

在这种情况下,你无法避免它。您必须指定列名称,对于具有重复名称的列,请使用别名。代码生成可以帮助这些列。

SELECT *是不好的做法 - 如果有人在其中一个表中添加了2GB的二进制列并填充它,你真的希望它被返回吗?

答案 1 :(得分:3)

生成所需列的一种简单方法是

select column_name+',' from information_schema.columns
where table_name='tt'
and column_name not in('ID')

答案 2 :(得分:3)

以及Oded的回答(100%同意)......

如果有人更改了基础表,则无论如何都需要查看维护(使用sp_refreshview)。列中的更改将不会自动显示在视图中。见"select * from table" vs "select colA, colB, etc. from table" interesting behaviour in SQL Server 2005

所以你的“反映在”MasterView“自动要求无论如何都不能满足

如果要确保视图是最新的,请使用WITH SCHEMABINDING,这将阻止更改基础表(直到删除或删除)。然后进行列更改,然后重新应用视图

答案 3 :(得分:1)

我遇到了同样的问题,请参阅下面的示例:

ALTER VIEW Summary AS SELECT * FROM Table1 AS t1 INNER JOIN Table2 AS t2 ON t1.Id = t2.Id

我遇到了您提到的错误,最简单的解决方案就是在*之前使用别名:

SELECT t1.* FROM Table1 AS t1 INNER JOIN Table2 AS t2 ON t1.Id = t2.Id

你不应该再看到这个错误了。

答案 4 :(得分:0)

最终,我根据Madhivanan的建议完成了这项工作。它类似于t-clausen.dk后来建议的(感谢你的努力),虽然我发现xml路径样式比游标/等级分区更优雅。

以下内容在运行时重新创建MasterView定义。基础表中的所有列都以表名为前缀,因此默认情况下,我可以在视图中包含两个具有相似名称的列。这单独解决了我原来的问题,但我还包含了“WHERE column_name NOT IN”子句,专门排除了永远不会在MasterView中使用的某些列。

create procedure Utility_RefreshMasterView 
as
begin

    declare @entity_columns varchar(max)
    declare @drop_view_sql varchar(max)
    declare @alter_view_definition_sql varchar(max)

    /* create comma separated string of columns from underlying tables aliased to avoid name collisions */
    select @entity_columns = stuff((
        select ','+table_name+'.['+column_name+'] AS ['+table_name+'_'+column_name+']' 
        from information_schema.columns
        where table_name IN ('entity_1', 'entity_2')
        and column_name not in ('column to exclude 1', 'column to exclude 2')
        for xml path('')), 1, 1, '')


    set @drop_view_sql = 'if exists (select * from sys.views where object_id = object_id(N''[dbo].[MasterView]'')) drop view MasterView'

    set @alter_view_definition_sql = 
    'create view MasterView as select ' + @entity_columns + '
    from entity_1
    inner join entity_2 on entity_2 .id = entity_1.id
    /* other joins follow */'

    exec (@drop_view_sql)
    exec (@alter_view_definition_sql)

end

答案 5 :(得分:0)

如果你有一个Select *然后你正在使用JOIN,结果可能包括具有相同名称且在视图中无法实现的列。如果你自己运行查询,工作正常但不是在创建时视图。

例如:

**Table A**
ID, CatalogName, CatalogDescription
**Table B**
ID, CatalogName, CatalogDescription
**After the JOIN query**
ID, CatalogName, CatalogDescription, ID, CatalogName, CatalogDescription
That's not possible in a View.

为视图中的每列指定唯一名称。使用*不是一个很好的做法。