我可以选择在SQL Server中选择0列吗?

9
我希望这个问题比类似的创建一个没有列的表更好。是的,我在询问大多数人认为毫无意义的学术问题。
很容易生成一个SELECT结果,其行数为0(但具有列),例如SELECT a = 1 WHERE 1 = 0
是否可能生成一个SELECT结果,其列数为0(但具有行)?例如SELECT NO COLUMNS FROM Foo。(这不是有效的T-SQL。)
我遇到了这个问题,因为我想插入几行数据,而不指定任何行数据。例如(SQL Server 2005)。
CREATE TABLE Bar (id INT NOT NULL IDENTITY PRIMARY KEY)
INSERT INTO Bar SELECT NO COLUMNS FROM Foo
-- Invalid column name 'NO'.
-- An explicit value for the identity column in table 'Bar' can only be specified when a column list is used and IDENTITY_INSERT is ON.

可以在不指定任何列数据的情况下插入单行,例如:INSERT INTO Foo DEFAULT VALUES

可以查询行数的计数(而不从表中检索实际列数据),例如:SELECT COUNT(*) FROM Foo。 (但是,该结果集当然有一列。)

我尝试了一些类似的东西

INSERT INTO Bar () SELECT * FROM Foo
  -- Parameters supplied for object 'Bar' which is not a function.
  -- If the parameters are intended as a table hint, a WITH keyword is required.

并且

INSERT INTO Bar DEFAULT VALUES SELECT * FROM Foo
  -- which is a standalone INSERT statement followed by a standalone SELECT statement.

我可以用不同的方式完成我需要做的事情,但是支持退化情况的一致性似乎缺乏,这让我感到惊讶。

我阅读了BOL的相关部分,但没有看到任何内容。我很惊讶在谷歌上也找不到任何信息。


5
你需要做的就是在不创建实际数据库的情况下创建一个数据库。剩下的事情就很容易了。 - Tom Cabanski
4
“对于退化情况支持的明显不一致性”?这似乎是完全一致的——必须存在列。你真的是指“无法支持您特定的情况”吗? - S.Lott
3
我不会说这是“毫无意义的学术”-“愚蠢的”更为合适。 - OMG Ponies
2
这并不是无聊或毫无意义的问题,实际上是一个非常好的问题。0度关系在查询中非常有用。SQL不支持空列列表语法的事实也会产生其他后果 - 例如,这意味着您无法创建“空”键而不进行一些笨拙的解决方法。 - nvogel
@David,你能详细说明一下0度关系或“空”键如何有用吗? - Martin Smith
@David:一个“0度”关系没有数据。它不可能有任何意义。 - S.Lott
7个回答

8

这是SQL的一个重要限制,也是SQL不完全符合关系模型的原因之一。

正如您所知道的,Hugh Darwen为两个零度关系创造了DUM和DEE的名称。SQL没有它们的等价物。


为什么这是一个重要的限制?在什么情况下你需要它? - Martin Smith
4
它使得SQL比关系代数更不强大。或者换句话说,在SQL中,并非所有结果都可以仅通过关系表达式获得,因此该语言的正交性较差且更为复杂。例如,SQL使用EXISTS运算符来测试行的存在并将结果集转换为真值或假值。该EXISTS运算符仅在查询的某些位置有效。而在关系术语中,您只需编写“PROJECT(..)R”即可获得一个零度关系,其中包含0个或1个元组,然后将其整洁地连接到查询的任何其他部分。 - nvogel
3
空键可以用于单行变量或常量表,这些表只需在数据库中设置一次。在SQL中,您必须创建一个虚拟列和/或CHECK约束来强制只允许单行的键。如果要实现第二范式以满足FDs(如{}->{A}),则隐式需要支持空键。 - nvogel

4

不,这是SQL的限制。SQL有很多缺陷、矛盾和不对称之处。不幸的是,与其灵感来源并旨在用于处理工作的关系理论和代数不同,它不是数学上精确或完整的。


我不确定如何理解这个答案。当然,SQL并不完美,但它是一个工具,我不相信它被设计或者甚至构想出来是用于“数学上精确或完整的关系理论和代数” 。也许你对原始帖子的目的有更深入的了解。 - BradC

2
不,您所要求的是不可能实现的。SQL是一种查询语言,而您在所需行为中没有查询任何内容。无论您是否检索实际的表数据,在查询中都是无关紧要的,但必须检索一些数据。在您的COUNT(*)示例中,您正在(显然)检索计数。
实现您想要的唯一方法是查询您感兴趣的行数(即,在所需WHERE子句上执行COUNT(1)),然后循环遍历您在示例中使用的空单个插入语句该数量的次数。没有单个语句可以完成此操作的方式。

1

尝试

INSERT INTO Bar SELECT * FROM Foo

替代

INSERT INTO Bar () SELECT * FROM Foo

然而,数据类型和列数需要匹配(实际上,数据类型需要能够隐式转换)

还是你想要这个?

CREATE TABLE Bar (id INT NOT NULL IDENTITY PRIMARY KEY)
INSERT INTO Bar DEFAULT VALUES

或者

CREATE TABLE Sequence2 (ID INT IDENTITY not null PRIMARY KEY,
            Somedate DATETIME DEFAULT GETDATE() not null,
            SomeID INT DEFAULT 0 not null)
GO

INSERT INTO Sequence2 DEFAULT VALUES

参见: 如何仅有标识列的情况下向表中插入值

1
他在问题中特别列出了那种情况。你为什么认为这回答了他的问题呢...? - Adam Robinson

1

不行。选择必须至少有一列。

我遇到这个问题是因为我想要插入多行,但并未指定它们的任何列数据。例如(SQL Server 2005)

啊,我有点理解你的目标。您想要插入没有实际值(在任何列中)的“占位符行”,并且这些列将在稍后填充。

不,这是不可能的。即使要插入5行“完全空白”的行,您如何稍后更新它们? (如果您在WHERE子句中没有任何参考资料)

我称之为“电子表格思维”。 SQL不是电子表格,而是数据库。

我只需创建一个人工密钥(带有身份验证的INT),然后如果对您没有任何用处,则稍后忽略它。


0
Declare @count as int
select @count = count(*) from mytable
select @count
create table #test (test int identity)
while @count>0
Begin
insert into #test default values
set @count= @count-1
ENd

select * from #test

这个能满足你的需求吗?


0
如果我没记错的话,SELECT NULL FROM table_name; 是有效的语法,但我不确定这是否算作零列或一列(每行包含NULL)。

2
这将是一列,每行的值都为NULL - Adam Robinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接