66

Is there any RDBMS that implements something like SELECT * EXCEPT? What I'm after is getting all of the fields except a specific TEXT/BLOB field, and I'd like to just select everything else.

Almost daily I complain to my coworkers that someone should implement this... It's terribly annoying that it doesn't exist.

Edit: I understand everyone's concern for SELECT *. I know the risks associated with SELECT *. However, this, at least in my situation, would not be used for any Production level code, or even Development level code; strictly for debugging, when I need to see all of the values easily.

As I've stated in some of the comments, where I work is strictly a commandline shop, doing everything over ssh. This makes it difficult to use any gui tools (external connections to the database aren't allowed), etc etc.

Thanks for the suggestions though.

Chris Catignani
  • 5,040
  • 16
  • 42
  • 49
Glen Solsberry
  • 11,960
  • 15
  • 69
  • 94
  • The EXCEPT keyword does exist within SQL Server, although it's not intended to be used how you would like in your question. It performs a DIFFERENCE UNION between two resultsets to give you a resultset of "records" that exist in the first resultset but don't exist in the second resultset – Russ Cam Feb 02 '09 at 17:42
  • 7
    It suck that this doesn't exist. – VISQL Jun 29 '12 at 23:51
  • 1
    possible duplicate of [SQL exclude a column using SELECT \* \[except columnA\] FROM tableA?](http://stackoverflow.com/questions/729197/sql-exclude-a-column-using-select-except-columna-from-tablea) – billinkc Mar 31 '15 at 21:01
  • @VISQL Now it exists – Lukasz Szozda Feb 27 '18 at 18:42
  • @lad2025 What variant of SQL? Could you share a link? That's pretty interesting. – VISQL Feb 28 '18 at 11:59
  • 1
    @VISQL Please check my answer https://stackoverflow.com/a/49015504/5070879 – Lukasz Szozda Feb 28 '18 at 17:12

15 Answers15

39

As others have said, it is not a good idea to do this in a query because it is prone to issues when someone changes the table structure in the future. However, there is a way to do this... and I can't believe I'm actually suggesting this, but in the spirit of answering the ACTUAL question...

Do it with dynamic SQL... this does all the columns except the "description" column. You could easily turn this into a function or stored proc.

declare @sql varchar(8000),
    @table_id int,
    @col_id int

set @sql = 'select '

select @table_id = id from sysobjects where name = 'MY_Table'

select @col_id = min(colid) from syscolumns where id = @table_id and name <> 'description'
while (@col_id is not null) begin
    select @sql = @sql + name from syscolumns where id = @table_id and colid = @col_id

    select @col_id = min(colid) from syscolumns where id = @table_id and colid > @col_id and name <> 'description'
    if (@col_id is not null) set @sql = @sql + ','
    print @sql
end

set @sql = @sql + ' from MY_table'

exec @sql
Jasmine
  • 4,003
  • 2
  • 29
  • 39
  • 18
    And in the spirit of answering the actual question, you win the prize. – Glen Solsberry Jan 05 '09 at 17:47
  • 3
    I can actually think of several reasons why you might need to do this without being insane. Plus it was an interesting question, regardless of the issues, it was just fun to figure out :) – Jasmine Jan 08 '09 at 23:00
  • 3
    First, thanks for answering the question rather than opining on whether the person should be doing the thing or not. One prime scenario for doing this would be creating a view, which you want to have pick up the underlying table columns if they change, and will be using in other select statements which pick specific columns. – Mark Shapiro Sep 15 '15 at 15:36
  • "exec @sql" gets me "The Name ' (insert 644 out of 680 characters of my SQL statement variable here) ' is not a valid identifier). Should be "exec (@sql)" – Rebeccah Dec 16 '16 at 22:04
  • @Rebeccah - usually that means you've got a syntax error in your statement somewhere. Typically it's un-balanced quotation marks. Dynamic sql is prone to that, it's easy to get confused with all the quotey marks everywhere. – Jasmine Dec 19 '16 at 16:26
  • @Jasmine I'm currently researching how to write a trigger which fires if any column of the table changes *except* one. I really want all other columns to be "dynamic" so I don't need to change the trigger function for each change in table structure. So **thank you** for answering the question. Although I'm not quite sure this will work in a trigger. – exhuma Sep 17 '18 at 08:48
  • @Jasmine - I really like the spirit, although I find the solution very impractical due to the length of code required - upvote – xorcus Nov 09 '20 at 13:24
25

Create a view on the table which doesn't include the blob columns

Paul Dixon
  • 295,876
  • 54
  • 310
  • 348
  • 2
    +1: this is quite reasonable - and no SELECT * allowed here as well. – Otávio Décio Jan 05 '09 at 17:24
  • 3
    Requires modifying the view if the source table changes. If you're going to use SELECT * on that, might as well just select the columns that you really want to begin with. – Brian Knoblauch Jan 05 '09 at 17:28
  • 1
    It saves you from typing those columns over and over though. For a developer's use in debugging it's not a bad idea. – Tom H Jan 05 '09 at 17:37
  • 4
    I have cut and paste on my fancy new computer. :-) – Brian Knoblauch Jan 05 '09 at 17:47
  • That's great, if you always want to keep that select statement (and any others like it) sitting around. I have enough clutter on my desktop. It's also more work to open a file, copy, and paste then it is to do a simple select, – Tom H Jan 05 '09 at 18:31
15

Is there any RDBMS that implements something like SELECT * EXCEPT?

Yes, Google Big Query implements SELECT * EXCEPT:

A SELECT * EXCEPT statement specifies the names of one or more columns to exclude from the result. All matching column names are omitted from the output.

WITH orders AS(
  SELECT 5 as order_id,
  "sprocket" as item_name,
  200 as quantity
)
SELECT * EXCEPT (order_id)
FROM orders;

Output:

+-----------+----------+
| item_name | quantity |
+-----------+----------+
| sprocket  | 200      |
+-----------+----------+

EDIT:

H2 database also supports SELECT * EXCEPT (col1, col2, ...) syntax.

Wildcard expression

A wildcard expression in a SELECT statement. A wildcard expression represents all visible columns. Some columns can be excluded with optional EXCEPT clause.


EDIT 2:

Hive supports: REGEX Column Specification

A SELECT statement can take regex-based column specification in Hive releases prior to 0.13.0, or in 0.13.0 and later releases if the configuration property hive.support.quoted.identifiers is set to none.

The following query selects all columns except ds and hr.

SELECT `(ds|hr)?+.+` FROM sales

EDIT 3:

Snowflake also now supports: SELECT * EXCEPT (and a RENAME option equivalent to REPLACE in BigQuery)

EXCLUDE col_name EXCLUDE (col_name, col_name, ...)

When you select all columns (SELECT *), specifies the columns that should be excluded from the results.

RENAME col_name AS col_alias RENAME (col_name AS col_alias, col_name AS col_alias, ...)

When you select all columns (SELECT *), specifies the column aliases that should be used in the results.


and so does Databricks SQL (since Runtime 11.0)

star_clause
   [ { table_name | view_name } . ] * [ except_clause ]

except_clause
   EXCEPT ( { column_name | field_name } [, ...] )

and also DuckDB

-- select all columns except the city column from the addresses table
SELECT * EXCLUDE (city) FROM addresses;
-- select all columns from the addresses table, but replace city with LOWER(city)
SELECT * REPLACE (LOWER(city) AS city) FROM addresses;
-- select all columns matching the given regex from the table
SELECT COLUMNS('number\d+') FROM addresses;
Paul Vernon
  • 3,818
  • 1
  • 10
  • 23
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
9

DB2 allows for this. Columns have an attribute/specifier of Hidden.

From the syscolumns documentation

HIDDEN
CHAR(1) NOT NULL WITH DEFAULT 'N'
Indicates whether the column is implicitly hidden:

P Partially hidden. The column is implicitly hidden from SELECT *.

N Not hidden. The column is visible to all SQL statements.

Create table documentation As part of creating your column, you would specify the IMPLICITLY HIDDEN modifier

An example DDL from Implicitly Hidden Columns follows

CREATE TABLE T1
(C1 SMALLINT NOT NULL,
C2 CHAR(10) IMPLICITLY HIDDEN,
C3 TIMESTAMP)
IN DB.TS;

Whether this capability is such a deal maker to drive the adoption of DB2 is left as an exercise to future readers.

billinkc
  • 59,250
  • 9
  • 102
  • 159
5

Is there any RDBMS that implements something like SELECT * EXCEPT

Yes! The truly relational language Tutorial D allows projection to be expressed in terms of the attributes to be removed instead of the ones to be kept e.g.

my_relvar { ALL BUT description }

In fact, its equivalent to SQL's SELECT * is { ALL BUT }.

Your proposal for SQL is a worthy one but I heard it has already been put to the SQL standard's committee by the users' group and rejected by the vendor's group :(

It has also been explicitly requested for SQL Server but the request was closed as 'won't fix'.

onedaywhen
  • 55,269
  • 12
  • 100
  • 138
4

Yes, finally there is :) SQL Standard 2016 defines Polymorphic Table Functions

SQL:2016 introduces polymorphic table functions (PTF) that don't need to specify the result type upfront. Instead, they can provide a describe component procedure that determines the return type at run time. Neither the author of the PTF nor the user of the PTF need to declare the returned columns in advance.

PTFs as described by SQL:2016 are not yet available in any tested database.10 Interested readers may refer to the free technical report “Polymorphic table functions in SQL” released by ISO. The following are some of the examples discussed in the report:

  • CSVreader, which reads the header line of a CVS file to determine the number and names of the return columns

  • Pivot (actually unpivot), which turns column groups into rows (example: phonetype, phonenumber) -- me: no more harcoded strings :)

  • TopNplus, which passes through N rows per partition and one extra row with the totals of the remaining rows


Oracle 18c implements this mechanism. 18c Skip_col Polymorphic Table Function Example Oracle Live SQL and Skip_col Polymorphic Table Function Example

This example shows how to skip data based on name/specific datatype:

CREATE PACKAGE skip_col_pkg AS  
  -- OVERLOAD 1: Skip by name 
  FUNCTION skip_col(tab TABLE,  col columns)  
           RETURN TABLE PIPELINED ROW POLYMORPHIC USING skip_col_pkg;  
  
  FUNCTION describe(tab IN OUT dbms_tf.table_t,   
                    col        dbms_tf.columns_t)  
           RETURN dbms_tf.describe_t;  
  
  -- OVERLOAD 2: Skip by type --  
  FUNCTION skip_col(tab       TABLE,   
                    type_name VARCHAR2,  
                    flip      VARCHAR2 DEFAULT 'False')   
           RETURN TABLE PIPELINED ROW POLYMORPHIC USING skip_col_pkg;  
  
  FUNCTION describe(tab       IN OUT dbms_tf.table_t,   
                    type_name        VARCHAR2,   
                    flip             VARCHAR2 DEFAULT 'False')   
           RETURN dbms_tf.describe_t;  
END skip_col_pkg;

and body:

CREATE PACKAGE BODY skip_col_pkg AS  
  
/* OVERLOAD 1: Skip by name   
 * NAME:  skip_col_pkg.skip_col   
 * ALIAS: skip_col_by_name  
 *  
 * PARAMETERS:  
 * tab - The input table  
 * col - The name of the columns to drop from the output  
 *  
 * DESCRIPTION:  
 *   This PTF removes all the input columns listed in col from the output  
 *   of the PTF.  
*/   
  FUNCTION  describe(tab IN OUT dbms_tf.table_t,   
                     col        dbms_tf.columns_t)  
            RETURN dbms_tf.describe_t  
  AS   
    new_cols dbms_tf.columns_new_t;  
    col_id   PLS_INTEGER := 1;  
  BEGIN   
    FOR i IN 1 .. tab.column.count() LOOP  
      FOR j IN 1 .. col.count() LOOP  
      tab.column(i).pass_through := tab.column(i).description.name != col(j);  
        EXIT WHEN NOT tab.column(i).pass_through;  
      END LOOP;  
    END LOOP;  
  
    RETURN NULL;  
  END;  
    
 /* OVERLOAD 2: Skip by type  
 * NAME:  skip_col_pkg.skip_col   
 * ALIAS: skip_col_by_type  
 *  
 * PARAMETERS:  
 *   tab       - Input table  
 *   type_name - A string representing the type of columns to skip  
 *   flip      - 'False' [default] => Match columns with given type_name  
 *               otherwise         => Ignore columns with given type_name  
 *  
 * DESCRIPTION:  
 *   This PTF removes the given type of columns from the given table.   
*/   
  
  FUNCTION describe(tab       IN OUT dbms_tf.table_t,   
                    type_name        VARCHAR2,   
                    flip             VARCHAR2 DEFAULT 'False')   
           RETURN dbms_tf.describe_t   
  AS   
    typ CONSTANT VARCHAR2(1024) := upper(trim(type_name));  
  BEGIN   
    FOR i IN 1 .. tab.column.count() LOOP  
       tab.column(i).pass_through :=   
         CASE upper(substr(flip,1,1))  
           WHEN 'F' THEN dbms_tf.column_type_name(tab.column(i).description)
     !=typ  
           ELSE          dbms_tf.column_type_name(tab.column(i).description) 
     =typ  
         END /* case */;  
    END LOOP;  
  
    RETURN NULL;  
  END;  
  
END skip_col_pkg;  

And sample usage:

-- skip number cols
SELECT * FROM skip_col_pkg.skip_col(scott.dept, 'number'); 

-- only number cols
SELECT * FROM skip_col_pkg.skip_col(scott.dept, 'number', flip => 'True') 

-- skip defined columns
SELECT *   
FROM skip_col_pkg.skip_col(scott.emp, columns(comm, hiredate, mgr))  
WHERE deptno = 20;

I highly recommend to read entire example(creating standalone functions instead of package calls).

You could easily overload skip method for example: skip columns that does not start/end with specific prefix/suffix.

db<>fidde demo

Related: How to Dynamically Change the Columns in a SQL Query By Chris Saxon

Community
  • 1
  • 1
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
2

Stay away from SELECT *, you are setting yourself for trouble. Always specify exactly which columns you want. It is in fact quite refreshing that the "feature" you are asking for doesn't exist.

Otávio Décio
  • 73,752
  • 17
  • 161
  • 228
  • Luckily, our tables almost never change. I'm thinking of this specifically for debugging problems, where I need all of the other fields, except for the BLOB. – Glen Solsberry Jan 05 '09 at 17:21
  • in that specific case, I agree that it'd be nice to have. – Michael Haren Jan 05 '09 at 17:21
  • The operating word here is *almost*. Also, any good sql tool will allow you to click and choose what you want without polluting the language with such contraption. – Otávio Décio Jan 05 '09 at 17:22
  • @gms8994, in the case of debugging, most enterprise RDBMSs will automatically script out the select statement for you, which includes all columns. Then just remove your 'yucky' column and you're good to go. – Kon Jan 05 '09 at 17:23
  • ocdecio/fallen888: that implies that you're using some gui tool, which we do not. strictly commandline here. – Glen Solsberry Jan 05 '09 at 17:32
  • 5
    This doesn't answer the question. Sometimes this feature would be useful even if open to the same abuse as `*`. Specifically the times I have wanted to do something like this are when cloning a row in a table with an identity column. Then it would be handy to be able to do `INSERT ... SELECT ALL BUT id ...` – Martin Smith Aug 10 '13 at 09:37
  • Another example where this is useful, similar to Martin Smith's example, is when restoring (cloning) rows in a historyaudit table to the table that was being audited, where the historyaudit table has audit fields that are not present in the table being audited. – Rebeccah Dec 16 '16 at 21:31
  • Actually, in my case it'd be more dangerous *not* to use `*` – I dump tables to test that my ETL scripts haven't introduced any regressions, and run diffs on the dumps comparing them to prev run, but I have to script out the id columns (which are just noise in the diffs). If I explicitly specified columns instead of `*`, those would not show in the diffs if I later introduce columns in the ETL program but not the dump-script. So it depends on use-case what's safe and what's not. There's no unfortunately no rule of thumb that lets you avoid actually thinking about your particular problem. – unhammer Aug 19 '19 at 10:07
2

I believe the rationale for it not existing is that the author of a query should (for performance sake) only request what they're going to look at/need (and therefore know what columns to specify) -- if someone adds a couple more blobs in the future, you'd be pulling back potentially large fields you're not going to need.

Rowland Shaw
  • 37,700
  • 14
  • 97
  • 166
1

Temp table option here, just drop the columns not required and select * from the altered temp table.

/* Get the data into a temp table */
    SELECT * INTO #TempTable
    FROM 
    table

/* Drop the columns that are not needed */
    ALTER TABLE #TempTable
    DROP COLUMN [columnname]

SELECT * from #TempTable
Mike
  • 537
  • 1
  • 8
  • 18
0
declare @sql nvarchar(max)
        @table char(10)
set @sql = 'select '
set @table = 'table_name'

SELECT @sql = @sql + '[' + COLUMN_NAME + '],'
FROM   INFORMATION_SCHEMA.Columns
WHERE  TABLE_NAME = @table
   and COLUMN_NAME <> 'omitted_column_name'
SET    @sql = substring(@sql,1,len(@sql)-1) + ' from ' + @table

EXEC (@sql);
kzh
  • 19,810
  • 13
  • 73
  • 97
0

It's an old question, but I hope this answer can still be helpful to others. It can also be modified to add more than one except fields. This can be very handy if you want to unpivot a table with many columns.

DECLARE @SQL NVARCHAR(MAX)
SELECT @SQL = COALESCE(@SQL + ', ', ' ' ) + name FROM sys.columns WHERE name <> 'colName' AND object_id = (SELECT id FROM sysobjects WHERE name = 'tblName')
SELECT @SQL = 'SELECT ' + @SQL + ' FROM ' + 'tblName'
EXEC sp_executesql  @SQL

Stored Procedure:

usp_SelectAllExcept 'tblname', 'colname'

ALTER PROCEDURE [dbo].[usp_SelectAllExcept]
(
  @tblName SYSNAME
 ,@exception VARCHAR(500)
)
AS

DECLARE @SQL NVARCHAR(MAX)

SELECT @SQL = COALESCE(@SQL + ', ', ' ' ) + name from sys.columns where name <> @exception and object_id = (Select id from sysobjects where name = @tblName)
SELECT @SQL = 'SELECT ' + @SQL + ' FROM ' + @tblName

EXEC sp_executesql @SQL
Weihui Guo
  • 3,669
  • 5
  • 34
  • 56
0

I needed something like what @Glen asks for easing my life with HASHBYTES().

My inspiration was @Jasmine and @Zerubbabel answers. In my case I've different schemas, so the same table name appears more than once at sys.objects. As this may help someone with the same scenario, here it goes:

ALTER PROCEDURE [dbo].[_getLineExceptCol]

@table SYSNAME,
@schema SYSNAME,
@LineId int,
@exception VARCHAR(500)

AS

DECLARE @SQL NVARCHAR(MAX)

BEGIN

SET NOCOUNT ON;

SELECT @SQL = COALESCE(@SQL + ', ', ' ' ) + name 
FROM sys.columns 
WHERE name <> @exception 
AND object_id = (SELECT object_id FROM sys.objects 
                 WHERE name LIKE @table 
                 AND schema_id = (SELECT schema_id FROM sys.schemas WHERE name LIKE @schema))   

SELECT @SQL = 'SELECT ' + @SQL + ' FROM ' + @schema + '.' + @table + ' WHERE Id = ' + CAST(@LineId AS nvarchar(50))

EXEC(@SQL)
END
GO
rantunes
  • 5
  • 3
0

For the sake of completeness, this is possible in DremelSQL dialect, doing something like:

WITH orders AS
  (SELECT 5 as order_id,
  "foobar12" as item_name,
  800 as quantity)
SELECT * EXCEPT (order_id)
FROM orders;

Result:

+-----------+----------+
| item_name | quantity |
+-----------+----------+
| foobar12  | 800      |
+-----------+----------+

There also seems to be another way to do it here without Dremel.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
David Andrei Ned
  • 799
  • 1
  • 11
  • 28
0

Your question was about what RDBMS supports the * EXCEPT (...) syntax, so perhaps, looking at the jOOQ manual page for * EXCEPT can be useful in the future, as that page will keep track of new dialects supporting the syntax.

Currently (mid 2022), among the jOOQ supported RDBMS, at least BigQuery, H2, and Snowflake support the syntax natively. The others need to emulate it by listing the columns explicitly:

-- ACCESS, ASE, AURORA_MYSQL, AURORA_POSTGRES, COCKROACHDB, DB2, DERBY, EXASOL, 
-- FIREBIRD, HANA, HSQLDB, INFORMIX, MARIADB, MEMSQL, MYSQL, ORACLE, POSTGRES, 
-- REDSHIFT, SQLDATAWAREHOUSE, SQLITE, SQLSERVER, SYBASE, TERADATA, VERTICA, 
-- YUGABYTEDB
SELECT LANGUAGE.CD, LANGUAGE.DESCRIPTION
FROM LANGUAGE

-- BIGQUERY, H2
SELECT * EXCEPT (ID)
FROM LANGUAGE

-- SNOWFLAKE
SELECT * EXCLUDE (ID)
FROM LANGUAGE

Disclaimer: I work for the company behind jOOQ

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • Time to add Snowflake to your list Lukas? https://community.snowflake.com/s/article/6-37-Release-Notes-November-10-11-2022 – Paul Vernon Nov 16 '22 at 10:26
  • 1
    @PaulVernon: Cool, thanks a lot for the pointer! I've created a feature request here: https://github.com/jOOQ/jOOQ/issues/14230 – Lukas Eder Nov 16 '22 at 11:06
  • Looking around, Databricks too has `EXCEPT` (but not `RENAME`/`REPLACE`) on select * since runtime 11.0 https://docs.databricks.com/sql/language-manual/sql-ref-syntax-qry-select.html#syntax – Paul Vernon Nov 16 '22 at 11:49
  • And DuckDB... https://duckdb.org/docs/sql/query_syntax/select – Paul Vernon Nov 16 '22 at 13:04
-1

As others are saying: SELECT * is a bad idea.

Some reasons:

  1. Get only what you need (anything more is a waste)
  2. Indexing (index what you need and you can get it more quickly. If you ask for a bunch of non-indexed columns, too, your query plans will suffer.
Michael Haren
  • 105,752
  • 40
  • 168
  • 205
  • I don't agree on your seconds point, because fetching columns has in first place nothing to do with indexing nor execution plans. You add an index to a column, if you want to join tables by columns or want to restrict data on columns (WHERE) in an eligible time. When you simply select five tables by joining them, it doesn't really matter if you select one or 200 columns (this is just a matter of fetching the data). – bobbel Mar 31 '16 at 14:56
  • 1
    @bobbel I must insist that indexes can absolutely improve retrieval beyond just finding the desired records, *if* they cover the requested columns. Covering indexes can yield a massive performance improvement by answering the entire query/join/etc. from the index itself -- without going to the underlying data that generated the index. – Michael Haren Mar 31 '16 at 22:37
  • 2
    Useful info, but doesn't really answer the question. – faintsignal Jun 05 '18 at 20:59