SELECT * EXCEPT

时间:2009-01-05 17:15:09

标签: sql

是否有任何RDBMS实现SELECT * EXCEPT之类的东西?我所追求的是获取除特定TEXT / BLOB字段之外的所有字段,我只想选择其他所有字段。

几乎每天我都会向我的同事抱怨有人应该实施这个......它非常烦人,不存在。

修改:我了解每个人对SELECT *的关注。我知道与SELECT *相关的风险。但是,至少在我的情况下,这不会用于任何生产级代码,甚至是开发级代码;严格用于调试,当我需要轻松查看所有值时。

正如我在一些评论中所说,我工作的地方严格来说是一个命令行商店,在ssh上做一切。这使得很难使用任何gui工具(不允许与数据库的外部连接)等。

感谢您的建议。

14 个答案:

答案 0 :(得分:33)

正如其他人所说,在查询中执行此操作并不是一个好主意,因为当有人在将来更改表结构时,它很容易出现问题。但是,有一种方法可以做到这一点......我无法相信我实际上是在暗示这一点,但本着回答实际问题的精神......

使用动态SQL执行此操作...这将执行除“description”列之外的所有列。您可以轻松将其转换为函数或存储过程。

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

答案 1 :(得分:24)

在表格上创建一个不包含blob列的视图

答案 2 :(得分:9)

DB2允许这样做。列的属性/说明符为Hidden

来自syscolumns documentation

  

HIDDEN
  CHAR(1)NOT NULL WITH DEFAULT'N'
  指示是否隐式隐藏列:

     

P部分隐藏。从SELECT *隐式隐藏该列。

     

N不隐藏。该列对所有SQL语句都可见。

Create table documentation在创建列时,您需要指定IMPLICITLY HIDDEN修饰符

来自Implicitly Hidden Columns的示例DDL跟随

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

这种能力是否是推动DB2采用的交易制定者,这仍然是未来读者的一种练习。

答案 3 :(得分:6)

  

是否有任何RDBMS实现SELECT * EXCEPT?

之类的东西

是的,Google Big Query实施了SELECT * EXCEPT

  

SELECT * EXCEPT语句指定要从结果中排除的一个或多个列的名称。输出中省略了所有匹配的列名称。

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

输出:

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

答案 4 :(得分:5)

  

是否有任何RDBMS实现SELECT * EXCEPT

之类的东西

是的!真正的关系语言Tutorial D允许以要删除的属性而不是要保留的属性来表示投影。

my_relvar { ALL BUT description }

事实上,它与SQL的SELECT *相当,是{ ALL BUT }

您对SQL的建议是值得的,但我听说它已被用户组提交给SQL标准委员会,并被供应商组拒绝:(

它也是explicitly requested for SQL Server,但请求已关闭,因为“无法修复”。

答案 5 :(得分:3)

远离SELECT *,你正在为自己设置麻烦。 始终准确指定所需的列。事实上,你所要求的“特征”并不存在,这是非常令人耳目一新的。

答案 6 :(得分:2)

我认为它不存在的理由是,查询的作者应该(为了性能)只请求他们将要查看/需要的内容(因此知道要指定的列) - 如果有人添加将来会有更多的斑点,你可能会撤回你不需要的大片土地。

答案 7 :(得分:2)

是的,最后有:) SQL Standard 2016定义了 Polymorphic Table Functions

  

SQL:2016引入了多态表函数(PTF),它们不需要预先指定结果类型。相反,它们可以提供描述组件过程,以确定运行时的返回类型。 PTF的作者和PTF的用户都不需要提前声明返回的列。

     

SQL:2016中描述的PTF尚未在任何经过​​测试的数据库中提供.10感兴趣的读者可以参考ISO发布的免费技术报告“SQL中的多态表函数”。以下是报告中讨论的一些例子:

     
      
  • CSVreader,它读取CVS文件的标题行以确定返回列的数量和名称

  •   
  • Pivot(实际上是unpivot),它将列组变成行(例如:phonetype,phonenumber) - me:没有更多的编码字符串:)

  •   
  • TopNplus,每个分区通过N行,另外一行包含剩余行的总数

  •   

Oracle 18c实现了这种机制。 18c Skip_col Polymorphic Table Function Example Oracle Live SQLSkip_col Polymorphic Table Function Example

此示例显示如何根据名称/特定数据类型跳过数据:

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;

和身体:

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;  

样本用法:

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

我强烈建议您阅读整个示例(创建独立函数而不是包调用)。

您可以轻松地重载skip方法,例如:跳过不以特定前缀/后缀开头/结尾的列。

<强> db<>fidde demo

答案 8 :(得分:0)

正如其他人所说:SELECT *是一个坏主意。

一些原因:

  1. 只获得你需要的东西(更多的东西是浪费)
  2. 索引(索引你需要的东西,你可以更快地得到它。如果你要求一堆非索引列,你的查询计划也会受到影响。

答案 9 :(得分: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);

答案 10 :(得分:0)

这是一个老问题,但我希望这个答案仍然可以对其他人有所帮助。它也可以修改为添加more than one except fields。如果您希望unpivot a table包含多列,这可能会非常方便。

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

存储过程:

usp_SelectAllExcept&#39; tblname&#39;,&#39; colname&#39;

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

答案 11 :(得分:0)

我需要的东西就像@Glen要求用HASHBYTES()来缓解我的生活。

我的灵感来自于@Jasmine和@Zerubbabel的答案。在我的情况下,我有不同的模式,因此相同的表名在sys.objects中出现不止一次。因为这可能会帮助那些具有相同场景的人,所以在这里:

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

答案 12 :(得分:0)

此处的临时表选项,只需删除不需要的列,然后从更改的临时表中选择*。

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

答案 13 :(得分:0)

为了完整起见,这可以在DremelSQL方言中执行,例如:

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

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

如果没有Dremel,似乎还有另一种方法here