SQL使用SELECT * [columnA除外] FROM tableA排除列?


733

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

SELECT * FROM tableA

有没有一种方法可以在不指定所有列的情况下从表中排除列?

SELECT * [except columnA] FROM tableA

我知道的唯一方法是手动指定所有列,并排除不需要的列。这确实很耗时,因此我正在寻找节省时间和精力的方法,并且在表包含更多/更少列的情况下,还可以进行将来的维护。


27
拥有此功能(而不是在生产代码中输入,但用于故障排除)将非常方便。示例:我有一个表,其中包含多个要查询的列,但是我想快速省略一两个文本列。
Micah B.

在使用openquery时,我需要这样做(尽管我需要MySQL中的功能而不是SQL Server中的功能)。我不得不使用SQL Server查询MySQL数据库。因为MySQL表具有固定宽度的char列,所以我无法使用SELECT *查询(OLE DB在映射这些列时遇到问题)。我无法指定正确的列,因为我无法直接访问MySQL数据库,但是SQL Server足以通知我固定宽度char列的名称...
jahu 2014年

2
我想添加另一个原因来执行此操作:SELECT DISTINCT *除了键列在没有其他人创建的重复行的情况下工作之外
取消删除

1
我同意这很费时间。这就是为什么我通常只需右键单击表,选择“选择前1000行”,然后删除不需要的列。
ThomasRones

2
不要忘记:在许多情况下,开发人员都不知道这些列,因为它们可以更改。这在数据仓库中很常见。6个月后,他们会增加一列,并且应在不更改代码的情况下进行选择。

Answers:


445

我同意所有人的观点...但是,如果我要做这样的事情,我可能会这样:

/* 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

222
效率低下...但很有创造力:)
GuillermoGutiérrez

1
美丽。我经常需要包括将两个临时表或一个临时表连接到另一个表,在该表中我不需要临时表中的所有列-尤其是因为将涉及分组。
VISQL 2012年

2
非常好。Sure解决了抽象列名称的问题。
烤面包机

1
@CeesTimmerman-如果您的查询涉及重复的列名,这是一个单独的问题,请避免使用哪种方法。Google“ SQL列重命名”或“ SQL列别名”。诸如SELECT table1.ID AS table1ID ...IIRC之类的东西。
制造商史蒂夫(Steve)2014年

3
@ToolmakerSteve这个问题的想法是只指定不需要的列。命名列需要指定特定表的所有列(例如20多个)。
Cees Timmerman 2014年

289

没有。

维护简便的最佳实践是仅指定必需的列。

至少有两个原因:

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

编辑(2011年7月):

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


3
我从来不知道关于拖拽列的事情,谢谢GBN,您又节省了一天。由于您的SQL专业知识,您必须赚很多

4
SELECT *存在有效的方案,尤其是在ETL例程中。我认为最好的答案是使用动态SQL。
mishkin 2014年

1
在某些情况下,您希望选择说出学生的所有数据以进行统计探索,但又不想破坏学生

3
“仅指定需要的列” -硬编码无义
RM海利

9
尽管像这样的答案获得了很多选票,但就我而言,它们没有任何价值。从概念上讲,能够“选择*除ABC”不再比该语言支持的“选择*”有问题。OP显然要求一种完成某项任务的方法。回答此问题的人无法知道OP是否要在生产代码中使用此代码,或者他们在为数据库开发一些代码时是否仅需要立即运行这样的查询,因此有关良好标准的讲座毫无贡献。
Itsme2003 '19

68

如果您不想手动输入每个列名,则可以Script Table As通过右键单击或在SSMS中进行查看来使用,如下所示:

在此处输入图片说明

然后,您将在“ 新建查询编辑器”窗口中获得整个选择查询,然后删除不需要的列,如下所示:

在此处输入图片说明

完成了


2
这比选择所有列名称然后在其中添加逗号更容易。
shaijut

68

在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所有内容。
2016年

43

您可以创建一个具有希望选择的列的视图,然后可以仅从select *该视图...


8
最初我的反应是“这比仅指定列还容易吗?” 但后来我决定从维护角度来看,这可能是一种改进。
制造商史蒂夫(Steve)2014年

1
这也支持查询优化器,而不是用临时表或动态SQL抵消它。
underscore_d

30

是的,有可能(但不建议这样做)。

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. ISNULL仅当该名称不是第一列名称时,才可以使用该功能在逗号前加上逗号。使用该QUOTENAME功能在列名称中支持空格和标点符号。
  5. 使用WHERE子句隐藏我们不想看到的列。
  6. 使用EXEC (@variable)(也称为动态SQL)在运行时解析列名。这是必需的,因为我们在编译时不知道列名。

谢谢!这是解决我的问题的关键。
安东尼奥

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

17

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

select top 1 * from table

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


13
看到来自SSMS拖着我的小费
GBN

11

基本上,您无法做自己想做的事-但是您可以获得正确的工具来帮助您简化工作。

如果查看Red-Gate的SQL Prompt,则可以键入“ SELECT * FROM MyTable”,然后将光标移到“ *”之后,然后按<TAB>展开字段列表,并删除这些字段。不需要

这不是一个完美的解决方案,而是一个不错的解决方案!:-)糟糕的是,MS SQL Server Management Studio的Intellisense仍然不够智能,无法提供此功能。


很好,但是问题是您的查询可能变得庞大。拥有“除外”功能(不是针对产品代码,而是临时查询)会很好。
Micah B.

8

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

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


13
这是可行的,但我会解雇这样做的人。
Lieven Keersmaekers,2009年

经典清理问题:将要保留的dfata复制到临时表中,截断大的dfata,然后重新填充临时表。您需要排除身份列。
Volker

8

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

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

请享用。


7

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


6

总而言之,您无法做到这一点,但是我不同意上面的所有评论,在某些情况下,您可以合法地使用*当您创建嵌套查询以从整个列表中选择特定范围时(例如分页)为什么在内部选择了外部选择语句后,世界上每个人都想指定它呢?


进行联接时,是否可以使用“ innername。*”的某些变体表示内部列,类似于“ SELECT table1。* ...”?
制造商史蒂夫(Steve)2014年

6
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)

更新:

如果您更频繁地使用存储过程,则还可以创建一个存储过程来完成此任务。在此示例中,我使用了内置的STRING_SPLIT()(可在SQL Server 2016+上使用),但是如果需要,可以使用大量示例来了解如何在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';

5

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

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');

5

有没有一种方法可以在不指定所有列的情况下从表中排除列?

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

我认为您提出的语法是有价值的。实际上,关系数据库语言“教程D”具有非常相似的语法,其中关键字ALL BUT后跟一组属性(列)。

但是,SQL SELECT *已经变得非常脆弱(@Guffa的回答是一个典型的反对),因此我认为SELECT ALL BUT不会很快进入SQL标准。

我认为最好的“解决方法”是VIEW仅创建一个您想要的列SELECT * FROM ThatView


1
@underscore_d:我现在修改了答案。
一天,2016年

很酷,我同意你的最后两段。关于教程D的信息很有趣,尽管我倾向于同意那些认为select *值得怀疑的人的信息-对于需要一般处理数据表的临时性物品和程序非常有用,但对于构​​建(但没有更好的词)却不是那么有用“纯”查询。尽管如此,不符合ANSI标准并不意味着Microsoft不能像其他许多事情一样将其添加到他们的方言中,但是我怀疑他们是否愿意。
underscore_d

5

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

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

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

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

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


4

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语句

从officepark SELECT o.officepark,o.owner,o.squarefootage


虽然从理论上讲这可以回答问题,但最好在此处包括答案的基本部分,并提供链接以供参考。
巴尔加夫饶

3

我不知道任何支持此功能的数据库(SQL Server,MySQL,Oracle,PostgreSQL)。它绝对不是SQL标准的一部分,因此我认为您只需要指定所需的列即可。

您当然可以动态地构建SQL语句,然后让服务器执行它。但这为SQL注入打开了可能性。


3

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

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

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


1
是的,但是如果您有5个加入该怎么办?这个主意是SELECT * Except(tableName.ColumnName) FROM ...
Pawel Cioch 2014年

我觉得这很有用:)我对此一无所知,但这不是主题问题的答案。
Fka

3

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

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)

3
如果列数很大,比如说100,那么我们想选择所有列,但是要选择一列。有没有更好的方法?
KartikKannapur

5
这种错点。您将在第二个调用中选择“ id,date”,如果您打算这样做,则只需在第一位置进行即可。
keithpjolley

3

例如,如果要排除诸如密码之类的敏感大小写列,我可以这样做来隐藏值:

SELECT * , "" as password FROM tableName;


这个工作对我来说
阿伦·普拉萨德ES

1
当然,您绝对不要在数据库中存储明文密码。至少他们应该用盐和胡椒粉来
捣碎

2

好吧,通常的最佳做法是指定所需的列,而不是仅指定*。因此,您应该只声​​明要返回的字段。


2

一个学院建议一个很好的选择:

  • 在上一个查询(从中生成或获取数据的地方)中将SELECT INTO放入表中(完成后将删除该表)。这将为您创建结构。
  • 做一个CREATE脚本到新的查询窗口。
  • 删除不需要的列。将剩余的列格式化为1衬板,并粘贴为列列表。
  • 删除您创建的表。

完成...

这对我们有很大帮助。


1

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

它将列出所有列,而不是*。然后移除不需要的色谱柱。应该比自己输入要快得多。

然后,当您觉得这工作太多时,请获取Red Gate的SQL提示符,然后从tbl键入ssf,转到*并再次单击选项卡。


1

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

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


1

有时,同一程序必须处理不同的数据库结构。因此,我无法在程序中使用列列表来避免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

考虑详细说明/澄清您的问题/问题。
badfilms

1

我知道这个问题很旧,但是希望对您有所帮助。答案来自SQL Server论坛的讨论。您可以使其成为存储过程。还可以对其进行修改以添加多个(字段除外)。

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

0

这样做会不会更简单:

sp_help <table_name>

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


“比在这里提供的任何代码都要少键入代码”,比将Columns节点拖到查询编辑器或获取列表的任何其他高级方法要麻烦得多。我的意思是,列数为10的表怎么办?
underscore_d

0

您可以从devart.com获得SQL Complete,它不仅像Red Gate的SQL Prompt一样扩展了*通配符(如在cairnz的答案中所述),还提供了带有复选框的列选择器下拉列表,您可以在其中选中所有您希望在选择列表中找到的列,它们会自动为您插入(如果您取消选中该列,则该列会自动从选择列表中删除)。


0

在SSMS中,IntelliSenseAliasing是一种更简单的方法。尝试这个

  1. 右键单击文本编辑器,并确保已启用IntelliSense
  2. 使用别名[SELECT t。* FROM tablename t] 键入查询。
  3. 转到文本t。*并删除*,SSMS将自动列出别名表f的列。
然后,您可以快速指定想要的列,而 不必使用SSMS将选择写入另一个脚本,然后执行更多复制/粘贴操作。我经常用这个。


请问您是否可以指定排除列的答案?
Kamiccolo 2014年

@Kamiccolo-DuckWork描述的是手动操作。剪切并粘贴所需的列名称。他只是说这是一种无需输入太多内容即可更轻松地获得名称的方法。它不能帮助您编写一个查询“排除此列”。它只是帮助您创建所需的列列表,然后将其粘贴到查询中。
制造商史蒂夫(Steve)2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.