【问题标题】:Exclude a column using SELECT * [except columnA] FROM tableA?使用 SELECT * [except columnA] FROM tableA 排除列?
【发布时间】:2010-10-18 06:28:33
【问题描述】:

我们都知道要从表中选择所有列,我们可以使用

SELECT * FROM tableA

有没有办法在不指定所有列的情况下从表中排除列?

SELECT * [except columnA] FROM tableA

我知道的唯一方法是手动指定所有列并排除不需要的列。这真的很耗时,所以我正在寻找方法来节省时间和精力,以及如果表有更多/更少的列,以及将来的维护。

【问题讨论】:

  • 如果有这个功能会很方便,不是放入生产代码,而是用于故障排除。示例:我有一个表,其中有几个我查询的列,但我想快速省略一两列文本。
  • 我想添加另一个这样做的理由:SELECT DISTINCT * 除了键列可以在没有其他人创建的重复行的情况下工作
  • 我同意这很耗时。这就是为什么我通常只是右键单击表格,选择“选择前 1000 行”,然后删除我不想要的列。
  • 不要忘记:在许多情况下,开发人员不知道列,因为它们可以更改。这在数据仓库中很典型。 6 个月后,他们添加了一个额外的列,应该在不更改代码的情况下选择它。
  • 这样的特性有很多用例(从 SELECT * 中排除 n 列,而不是 1 列),它真的应该被添加到 SQL 的 ANSI 标准中。

标签: sql sql-server tsql


【解决方案1】:

你可以这样试试:

/* Get the data into a temp table */
SELECT * INTO #TempTable
FROM YourTable
/* Drop the columns that are not needed */
ALTER TABLE #TempTable
DROP COLUMN ColumnToDrop
/* Get results and drop temp table */
SELECT * FROM #TempTable
DROP TABLE #TempTable

【讨论】:

  • 效率低下...但很有创意:)
  • 美丽。我经常需要加入两个临时表或一个临时表到另一个我不需要临时表中的所有列的表 - 特别是因为会涉及到分组。
  • 非常好。当然可以解决抽象出列名的问题。
  • @CeesTimmerman - 如果您有一个涉及重复列名的查询,这是一个单独的问题,无论您采用哪种方法。谷歌“SQL 列重命名”或“SQL 列别名”。类似于SELECT table1.ID AS table1ID ...,IIRC。
  • @ToolmakerSteve 这个问题的想法是只指定您不需要的列。命名列需要指定特定表的所有列,例如 20 多个列。
【解决方案2】:

没有。

Maintenance-light 最佳实践是仅指定所需的列。

至少有两个原因:

  • 这使您的客户端和数据库之间的合同稳定。每次都使用相同的数据
  • 性能,涵盖索引

编辑(2011 年 7 月):

如果您从对象资源管理器中拖动表的 Columns 节点,它会在查询窗口中为您放置一个列的 CSV 列表,从而实现您的目标之一

【讨论】:

  • SELECT * 有一些有效的场景,尤其是在 ETL 例程中。我认为这里最好的答案是动态 SQL。
  • 在某些情况下,您希望选择学生的所有数据进行统计探索,但又不想将学生 ID 本身拉下来以保护隐私
  • 如果没有别的,我很高兴我阅读了这篇文章以了解 CSV 技巧。这就是为什么提供有关该主题的背景和信息比直接回答更重要的原因。为此我+1。谢谢
  • 虽然这样的答案获得了很多选票,但就我而言,它们没有任何价值。从概念上讲,能够“选择 * 除 ABC”与该语言支持的“选择 *”相比没有问题。 OP显然是在寻求一种完成某事的方法。回答这个问题的人无法知道 OP 是否想在生产代码中使用它,或者他们是否只是在为数据库开发一些代码时立即需要运行这样的查询,所以关于良好标准的讲座根本没有任何价值。
  • 当列列表是动态的时候就不那么容易了。
【解决方案3】:

如果您不想手动编写每个列名,您可以通过在 SSMS 中右键单击 tableview 来使用 Script Table As > 像这样:

然后您将在新查询编辑器窗口中获得整个选择查询,然后像这样删除不需要的列:

完成

【讨论】:

  • 这比selecting所有列名然后添加逗号更容易。
  • 你在这里假设什么 GUI 程序?
  • @wheredidthatnamecomefrom:这是 SSMS,这不是假设。
  • 我一定没有看到解释的地方谢谢。
【解决方案4】:

在 SQL (SQL Server) 中自动执行此操作的方法是:

declare @cols varchar(max), @query varchar(max);
SELECT  @cols = STUFF
    (
        ( 
            SELECT DISTINCT '], [' + name
            FROM sys.columns
            where object_id = (
                select top 1 object_id from sys.objects
                where name = 'MyTable'
            )
            and name not in ('ColumnIDontWant1', 'ColumnIDontWant2')
            FOR XML PATH('')
        ), 1, 2, ''
    ) + ']';

SELECT @query = 'select ' + @cols + ' from MyTable';  
EXEC (@query);

【讨论】:

  • 如果您从 CTE 或其他子查询的结果中查询怎么办?一个简单的例子:您可能想要创建一个子查询,将row_number() 的结果附加到每一行,然后通过row_number 执行连接,然后从结果中选择除了row_number 之外的所有内容的加入。
【解决方案5】:

您可以创建一个包含您希望选择的列的视图,然后您可以从视图中 select *...

【讨论】:

  • 起初我的反应是“这怎么比只指定列更容易”?但后来我决定,从维护的角度来看,这可能是一种改进。
  • 这也支持查询优化器,而不是用临时表或动态 SQL 来抵消它。
  • @ToolmakerSteve 此外,如果您正在执行许多不同的查询而省略了那一列,从视图中选择 * 可以为您节省大量输入(就像您说的那样,如果您想要更改该列设置,例如,您添加了一个新列,您只需在视图中执行此操作,您可以不理会查询)。实际上,在大多数应用程序中,我尽可能地关注视图,只是为了尽可能缩短应用程序的 SQL。
【解决方案6】:

像 BigQuery 这样的现代 SQL 方言提出了一个出色的解决方案。

SELECT * EXCEPT(ColumnNameX, [ColumnNameY, ...])
FROM TableA

这是一种非常强大的 SQL 语法,可以避免由于表列名称更改而需要一直更新的一长列列。而且目前的SQL Server实现中缺少这个功能,很可惜。希望有一天,Microsoft Azure 对数据科学家更加友好。

数据科学家喜欢有一个快速的选项来缩短查询并删除一些列(由于重复或任何其他原因)。

https://cloud.google.com/bigquery/docs/reference/standard-sql/query-syntax#select-modifiers

【讨论】:

  • 哦,那太好了。谢谢!
  • 这太完美了!谢谢!
【解决方案7】:

是的,这是可能的(但不推荐)。

CREATE TABLE contact (contactid int, name varchar(100), dob datetime)
INSERT INTO contact SELECT 1, 'Joe', '1974-01-01'

DECLARE @columns varchar(8000)

SELECT @columns = ISNULL(@columns + ', ','') + QUOTENAME(column_name)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'contact' AND COLUMN_NAME <> 'dob'
ORDER BY ORDINAL_POSITION

EXEC ('SELECT ' + @columns + ' FROM contact')

代码说明

  1. 声明一个变量来存储一个逗号分隔的列名列表。这默认为 NULL。
  2. 使用系统视图来确定表中列的名称。
  3. 使用SELECT @variable = @variable + ... FROM 连接 列名。这种类型的SELECT 不返回结果集。这可能是未记录的行为,但适用于 SQL Server 的每个版本。作为替代方案,您可以使用 SET @variable = (SELECT ... FOR XML PATH('')) 连接字符串。
  4. 仅当逗号不是 第一列名称。 使用QUOTENAME 函数支持列名中的空格和标点符号。
  5. 使用WHERE 子句隐藏我们不想看到的列。
  6. 使用EXEC (@variable),也称为动态SQL,解决 运行时的列名。这是必需的,因为我们在编译时不知道列名。

【讨论】:

  • 我有一个问题:出于什么原因必须将第二个选择放入 EXEC 语句中?我已经看到它实际上是必要的,但我想知道为什么我不能简单地写SELECT @columns FROM contact
【解决方案8】:

就像其他人所说的那样,没有办法做到这一点,但是如果您使用的是 Sql Server,我使用的一个技巧是将输出更改为逗号分隔,然后执行

select top 1 * from table

并从输出窗口中剪切整个列列表。然后,您可以选择您想要的列,而无需全部输入。

【讨论】:

  • 查看我的关于从 SSMS 拖动的提示
【解决方案9】:

基本上,你不能做你想做的事 - 但你可以得到正确的工具来帮助你让事情变得更容易。

如果你查看 Red-Gate 的SQL Prompt,你可以输入“SELECT * FROM MyTable”,然后将光标移回“*”后,点击 展开字段列表,然后删除那几个你不需要的字段。

这不是一个完美的解决方案 - 但一个非常好的解决方案! :-) 太糟糕了,MS SQL Server Management Studio 的 Intellisense 仍然不够智能,无法提供此功能......

马克

【讨论】:

  • 这很好,但问题是您的查询可能会变得很大。拥有“例外”功能会很好,不是用于产品代码,而是用于临时查询。
【解决方案10】:

不,没有办法做到这一点。如果您的情况可行,也许您可​​以创建自定义视图

编辑 如果您的数据库支持执行动态 sql,您可以编写一个 SP 并将您不想看到的列传递给它,让它动态创建查询并返回结果给你。我认为这至少在 SQL Server 中是可行的

【讨论】:

  • 这是可行的,但我会解雇这样做的人。
  • 经典清理问题:将要保留的 dfata 复制到临时表中,截断大的,重新填充临时表。您需要排除身份列。
【解决方案11】:
DECLARE @SQL VARCHAR(max), @TableName sysname = 'YourTableName'

SELECT @SQL = COALESCE(@SQL + ', ', '') + Name 
FROM sys.columns
WHERE OBJECT_ID = OBJECT_ID(@TableName)
AND name NOT IN ('Not This', 'Or that');

SELECT @SQL = 'SELECT ' + @SQL + ' FROM ' + @TableName

EXEC (@SQL)

更新:

如果您更频繁地使用它,您还可以创建一个存储过程来处理此任务。 在此示例中,我使用了 SQL Server 2016+ 上可用的内置 STRING_SPLIT(), 但如果您需要,有大量示例说明如何在 SO 上手动创建它。

CREATE PROCEDURE [usp_select_without]
@schema_name sysname = N'dbo',
@table_name sysname,
@list_of_columns_excluded nvarchar(max),
@separator nchar(1) = N','
AS
BEGIN
 DECLARE 
 @SQL nvarchar(max),
 @full_table_name nvarchar(max) = CONCAT(@schema_name, N'.', @table_name);

 SELECT @SQL = COALESCE(@SQL + ', ', '') + QUOTENAME([Name])
 FROM sys.columns sc
 LEFT JOIN STRING_SPLIT(@list_of_columns_excluded, @separator) ss ON sc.[name] = ss.[value]
 WHERE sc.OBJECT_ID = OBJECT_ID(@full_table_name, N'u')
 AND ss.[value] IS NULL;

 SELECT @SQL = N'SELECT ' + @SQL + N' FROM ' + @full_table_name;
 EXEC(@SQL)
END

然后就是:

EXEC [usp_select_without] 
@table_name = N'Test_Table',
@list_of_columns_excluded = N'ID, Date, Name';

【讨论】:

    【解决方案12】:

    总之你不能这样做,但我不同意上面的所有评论,有“一些”场景你可以合法地使用 * 当您创建嵌套查询以从整个列表中选择特定范围(例如分页)时,为什么在内部选择语句中指定每个列?

    【讨论】:

    • 在进行连接时可以使用“innername.*”的一些变体来表示内部列,类似于“SELECT table1.* ...”吗?
    【解决方案13】:

    在 SQL Management Studio 中,您可以在对象资源管理器中展开列,然后将 Columns 树项拖到查询窗口中以获取以逗号分隔的列列表。

    【讨论】:

    • 这个答案被低估了。这是最简单快捷的方法。
    【解决方案14】:

    如果您使用的是 SQL Server Management Studio,请执行以下操作:

    1. 输入您想要的表格名称并选择它
    2. Alt+F1
    3. o/p 显示表中的列。
    4. 选择所需的列
    5. 复制并粘贴到您的选择查询中
    6. 触发查询。

    享受吧。

    【讨论】:

      【解决方案15】:

      如果您想排除敏感的大小写列,例如密码,我这样做是为了隐藏值:

      SELECT * , "" as password FROM tableName;

      【讨论】:

      • 虽然您当然不应该在数据库中存储明文密码。至少他们应该用盐和胡椒粉security.stackexchange.com/questions/3272/…
      • 在这个上获得An object or column name is missing or empty. For SELECT INTO statements, verify each column has a name. For other statements, look for empty alias names. Aliases defined as "" or [] are not allowed. Change the alias to a valid name.
      • 你测试过这个吗?传统上,在 SQL 中,这仍然会显示原始密码列,然后显示一个名为密码的新列,其中包含一个空白字符串。他们甚至可以有相同的名字。在简单的选择查询中,您的空白列不会覆盖原始列。并且在创建表或视图时,会出现重复列名的错误。
      【解决方案16】:

      如果我们谈论的是过程,它使用这个技巧来生成一个新的查询并立即执行

      SELECT LISTAGG((column_name), ', ') WITHIN GROUP (ORDER BY column_id)
      INTO var_list_of_columns
      FROM ALL_TAB_COLUMNS
      WHERE table_name = 'PUT_HERE_YOUR_TABLE'
      AND column_name NOT IN ('dont_want_this_column','neither_this_one','etc_column');
      

      【讨论】:

        【解决方案17】:

        有没有办法在不指定的情况下从表中排除列 所有列?

        以通常的方式使用声明性 SQL,不。

        我认为你提出的语法是值得的和好的。事实上,关系数据库语言“Tutorial D”的语法非常相似,其中关键字ALL BUT 后跟一组属性(列)。

        然而,SQL 的SELECT * 已经受到了很多批评(@Guffa 的回答是一个典型的反对意见),所以我认为SELECT ALL BUT 不会很快进入 SQL 标准。

        我认为最好的“解决方法”是创建一个 VIEW,其中只有您想要的列,然后是 SELECT * FROM ThatView

        【讨论】:

        • @underscore_d:我现在修改了答案。
        • 酷,我同意你的最后两段。关于教程 D 的信息很有趣,尽管我倾向于同意那些认为 select * 有问题的人 - 对于需要通用处理数据表的临时内容和程序非常有用,但对于构​​建(缺乏更好的词)“纯”查询。尽管如此,不符合 ANSI 标准并不意味着微软不能像许多其他事情一样将其添加到他们的方言中,但我怀疑他们是否会这样做。
        【解决方案18】:

        我不知道有任何数据库支持此功能(SQL Server、MySQL、Oracle、PostgreSQL)。它绝对不是 SQL 标准的一部分,所以我认为你必须只指定你想要的列。

        您当然可以动态构建 SQL 语句并让服务器执行它。但这开启了 SQL 注入的可能性。

        【讨论】:

          【解决方案19】:

          Postgres sql 有办法做到这一点

          请参考: http://www.postgresonline.com/journal/archives/41-How-to-SELECT-ALL-EXCEPT-some-columns-in-a-table.html

          信息架构黑客方式

          SELECT 'SELECT ' || array_to_string(ARRAY(SELECT 'o' || '.' || c.column_name
                  FROM information_schema.columns As c
                      WHERE table_name = 'officepark' 
                      AND  c.column_name NOT IN('officeparkid', 'contractor')
              ), ',') || ' FROM officepark As o' As sqlstmt
          

          以上对于我的特定示例表 - 生成一个看起来像这样的 sql 语句

          选择 o.officepark、o.owner、o.squarefootage FROM officepark As o

          【讨论】:

            【解决方案20】:

            解决此问题的最佳方法是使用视图,您可以创建包含所需列的视图并从中检索数据

            example
            
            mysql> SELECT * FROM calls;
            +----+------------+---------+
            | id | date       | user_id |
            +----+------------+---------+
            |  1 | 2016-06-22 |       1 |
            |  2 | 2016-06-22 |    NULL |
            |  3 | 2016-06-22 |    NULL |
            |  4 | 2016-06-23 |       2 |
            |  5 | 2016-06-23 |       1 |
            |  6 | 2016-06-23 |       1 |
            |  7 | 2016-06-23 |    NULL |
            +----+------------+---------+
            7 rows in set (0.06 sec)
            
            mysql> CREATE VIEW C_VIEW AS
                ->     SELECT id,date from calls;
            Query OK, 0 rows affected (0.20 sec)
            
            mysql> select * from C_VIEW;
            +----+------------+
            | id | date       |
            +----+------------+
            |  1 | 2016-06-22 |
            |  2 | 2016-06-22 |
            |  3 | 2016-06-22 |
            |  4 | 2016-06-23 |
            |  5 | 2016-06-23 |
            |  6 | 2016-06-23 |
            |  7 | 2016-06-23 |
            +----+------------+
            7 rows in set (0.00 sec)
            

            【讨论】:

            • 如果列数很大,比如 100,我们想选择所有列,但只有一个。有更好的方法吗?
            • 这种不切实际。您在第二次通话中选择“id,date”,如果您要这样做,请首先执行。
            【解决方案21】:

            我知道这有点老了,但我刚刚遇到了同样的问题,正在寻找答案。然后我让一位高级开发人员向我展示了一个非常简单的技巧。

            如果您使用的是 Management Studio 查询编辑器,请展开数据库,然后展开您从中选择的表,以便您可以看到列文件夹。

            在您的选择语句中,只需突出显示上面引用的列文件夹并将其拖放到查询窗口中。它将粘贴表的所有列,然后只需从列列表中删除标识列...

            【讨论】:

            • 是的,但是如果你有 5 个连接,那么我们的想法是 SELECT * Except(tableName.ColumnName) FROM ...
            • 我觉得这很有用:) 我不知道,但这不是主题问题的答案。
            【解决方案22】:

            嗯,一个常见的最佳实践是指定你想要的列,而不是仅仅指定 *.所以你应该只说明你希望你的选择返回哪些字段。

            【讨论】:

              【解决方案23】:

              在对象资源管理器中右键单击表格,选择前 1000 行

              它将列出所有列而不是 *.然后删除不需要的列。应该比自己输入要快得多。

              那当你觉得工作量有点大的时候,获取 Red Gate 的 SQL Prompt,从 tbl 输入 ssf,进入 * 再次点击 tab。

              【讨论】:

                【解决方案24】:

                一位同事建议了一个不错的选择:

                • 在前面的查询中执行 SELECT INTO(您在其中生成或获取 数据)到一个表中(完成后您将删除该表)。这会 为您创建结构。
                • 将脚本作为 CREATE 执行到新查询 窗户。
                • 删除不需要的列。格式化剩余的列 放入 1 衬里并粘贴为您的列列表。
                • 删除你的表 已创建。

                完成...

                这对我们帮助很大。

                【讨论】:

                  【解决方案25】:

                  在 Hive Sql 中你可以这样做:

                  set hive.support.quoted.identifiers=none;
                  select 
                      `(unwanted_col1|unwanted_col2|unwanted_col3)?+.+`
                  from database.table
                  

                  这会给你剩下的列

                  【讨论】:

                  • 这个正则表达式有缺陷。如果要排除 dayday_hour 两列,(day|day_hour)?+.+ 仍将匹配 day_hour 列。那是因为正则表达式引擎渴望|。虽然将顺序更改为(day_hour|day)?+.+ 可以解决此问题,但更好的方法是使用负前瞻,(?!(day|day_hour)$).+
                  【解决方案26】:

                  我经常在这种情况下使用的东西:

                  declare @colnames varchar(max)=''
                  
                  select @colnames=@colnames+','+name from syscolumns where object_id(tablename)=id and name not in (column3,column4)
                  
                  SET @colnames=RIGHT(@colnames,LEN(@colnames)-1)
                  

                  @colnames 看起来像 column1,column2,column5

                  【讨论】:

                    【解决方案27】:

                    有时同一个程序必须处理不同的数据库结构。所以我不能在程序中使用列列表来避免select语句中的错误。

                    * 给了我所有的可选字段。我在使用前检查数据表中是否存在字段。这就是我在select 中使用* 的原因。

                    这就是我处理排除字段的方式:

                    Dim da As New SqlDataAdapter("select * from table", cn)
                    da.FillSchema(dt, SchemaType.Source)
                    Dim fieldlist As String = ""
                    For Each DC As DataColumn In DT.Columns
                       If DC.ColumnName.ToLower <> excludefield Then
                        fieldlist = fieldlist &  DC.Columnname & ","
                       End If
                      Next
                    

                    【讨论】:

                    • 考虑详细说明/澄清您的问题/问题。
                    【解决方案28】:

                    BartoszX 建议的答案(存储过程)在使用视图而不是真实表格时对我不起作用。

                    这个想法和下面的代码(我的修复除外)属于 BartoszX。

                    为了使这适用于表和视图,请使用以下代码:

                    SET ANSI_NULLS ON
                    GO
                    
                    SET QUOTED_IDENTIFIER ON
                    GO
                    
                    CREATE PROCEDURE [dbo].[select_without]
                    @schema_name sysname = N'dbo',
                    @table_name sysname,
                    @list_of_columns_excluded nvarchar(max),
                    @separator nchar(1) = N','
                    AS
                    BEGIN
                     DECLARE 
                     @SQL nvarchar(max),
                     @full_table_name nvarchar(max) = CONCAT(@schema_name, N'.', @table_name);
                    
                     SELECT @SQL = COALESCE(@SQL + ', ', '') + QUOTENAME([Name])
                     FROM sys.columns sc
                     LEFT JOIN STRING_SPLIT(@list_of_columns_excluded, @separator) ss ON sc.[name] = ss.[value]
                     WHERE sc.OBJECT_ID = OBJECT_ID(@full_table_name)
                     AND ss.[value] IS NULL;
                    
                     SELECT @SQL = N'SELECT ' + @SQL + N' FROM ' + @full_table_name;
                     EXEC(@SQL)
                    END
                    GO
                    

                    【讨论】:

                      【解决方案29】:

                      我知道这个问题很老了,但我希望这仍然会有所帮助。答案的灵感来自SQL Server Forums 的讨论。您可以将其设为stored procedure。也可以修改为添加多个除了字段。

                      DECLARE @SQL NVARCHAR(MAX)
                      SELECT @SQL = COALESCE(@SQL + ', ', ' ' ) + name from sys.columns where name not in ('colName1','colName2') and object_id = (Select id from sysobjects where name = 'tblName')
                      SELECT @SQL = 'SELECT ' + @SQL + ' FROM ' + 'tblName'
                      EXEC sp_executesql  @SQL
                      

                      【讨论】:

                        【解决方案30】:

                        这样做不是更简单吗:

                        sp_help <table_name>
                        

                        -单击“Column_name”列>复制>粘贴(创建垂直列表)到新查询窗口中,只需在每个列值前面键入逗号...注释掉您不需要的列.. . 比这里提供的任何代码都少得多,而且仍然易于管理。

                        【讨论】:

                        • “比这里提供的任何代码都少得多键入”,并且比将 Columns 节点拖到查询编辑器或任何其他获取列表的高级方法要麻烦得多。我的意思是有很多 10 列的表呢?
                        猜你喜欢
                        • 2012-08-14
                        • 1970-01-01
                        • 1970-01-01
                        • 2022-11-01
                        • 2018-04-28
                        • 2019-10-03
                        • 1970-01-01
                        • 1970-01-01
                        • 2015-03-30
                        相关资源
                        最近更新 更多