你能在 SQL 中定义“文字”表吗?

Posted

技术标签:

【中文标题】你能在 SQL 中定义“文字”表吗?【英文标题】:Can you define "literal" tables in SQL? 【发布时间】:2010-11-02 09:16:52 【问题描述】:

是否有任何 SQL 子查询语法可以让您从字面上定义一个临时表?

例如,类似

SELECT
  MAX(count) AS max,
  COUNT(*) AS count
FROM
  (
    (1 AS id, 7 AS count),
    (2, 6),
    (3, 13),
    (4, 12),
    (5, 9)
  ) AS mytable
  INNER JOIN someothertable ON someothertable.id=mytable.id

这样可以省去两三个查询:创建临时表,将数据放入其中,然后在连接中使用它。

我正在使用 mysql,但对其他可以做类似事情的数据库感兴趣。

【问题讨论】:

【参考方案1】:

从 MariaDB v10.3.3 和 MySQL v8.0.19 开始,您现在可以完全做到这一点!

请参阅文档:MariaDB、MySQL

MariaDB:

WITH literaltable (id,count) AS (VALUES (1,7),(2,6),(3,13),(4,12),(5,9))
SELECT MAX(count) AS max,COUNT(*) AS count FROM literaltable

我在这里使用了WITH,因为 MariaDB 没有为VALUES ... 提供好的列名。您可以在没有列名的联合中使用它:

SELECT 1 AS id,7 AS count UNION ALL VALUES (2,6),(3,13),(4,12),(5,9) ORDER BY count DESC

虽然文档似乎没有提到它,但您甚至可以将其用作***查询:

VALUES (1,7),(2,6),(3,13),(4,12),(5,9) ORDER BY 2 DESC

实际的列名实际上只是第一行值,所以你甚至可以这样做(虽然它不优雅,而且你可能会遇到重复的列名错误):

SELECT MAX(`7`) AS max,COUNT(*) AS count FROM (VALUES (1,7),(2,6),(3,13),(4,12),(5,9)) literaltable

MySQL:

我现在没有要测试的 MySQL v8.0.19 实例,但根据文档,其中任何一个都应该可以工作:

SELECT MAX(column_1) AS max,COUNT(*) AS count FROM (VALUES ROW(1,7), ROW(2,6), ROW(3,13), ROW(4,12), ROW(5,9)) literaltable

SELECT MAX(data) AS max,COUNT(*) AS count FROM (VALUES ROW(1,7), ROW(2,6), ROW(3,13), ROW(4,12), ROW(5,9)) literaltable(id,data)

与 MariaDB 不同,MySQL 提供自动列名 column_0、column_1、column_2 等,并且还支持在引用子查询时重命名子查询的所有列。

我不确定,但this dev worklog page 似乎暗示 MySQL 也实现了更短的语法(省略“ROW”,如 MariaDB),或者他们将在不久的将来实现。

【讨论】:

【参考方案2】:

你可以在 PostgreSQL 中做到这一点:

=> select * from (values (1,7), (2,6), (3,13), (4,12), (5,9) ) x(id, count);
 id | count 
----+-------
  1 |     7
  2 |     6
  3 |    13
  4 |    12
  5 |     9

http://www.postgresql.org/docs/8.2/static/sql-values.html

【讨论】:

PostgreSQL FTW. 也适用于 Spark SQL。 关于 MySQL 的问题 起初我认为 x 是某种特殊的 PostgreSQL 东西,直到我意识到它与 as x (id, count) 相同【参考方案3】:

在 Microsoft T-SQL 2008 中,格式为:

SELECT a, b FROM (VALUES (1, 2), (3, 4), (5, 6), (7, 8), (9, 10) ) AS MyTable(a, b)

即正如上面提到的乔纳森,但没有'table'关键字。

见:

FROM (T-SQL MSDN docs)(在派生表下)和 Table Value Constructor (T-SQL MSDN docs)

【讨论】:

【参考方案4】:

总之,是的。如果您的 SQL 产品支持公用表表达式 (CTE) 甚至更好的 IMO,即比使用子查询更容易,而且可以多次使用相同的 CTE,例如在 SQL Server 2005 及更高版本中“创建”一个 0 到 999 之间唯一整数的序列表:

WITH Digits (nbr) AS 
(
 SELECT 0 AS nbr UNION ALL SELECT 1 UNION ALL SELECT 2 
 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 
 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 
 UNION ALL SELECT 9 
), 
Sequence (seq) AS
(
 SELECT Units.nbr + Tens.nbr + Hundreds.nbr 
   FROM Digits AS Units
        CROSS JOIN Digits AS Tens
        CROSS JOIN Digits AS Hundreds
)
SELECT S1.seq 
  FROM Sequence AS S1;

除了你实际上会对序列表做一些有用的事情,例如解析基表中 VARCHAR 列中的字符。

但是,如果您使用这个表,它只包含文字值、多次或多次查询,那么为什么不首先将其设为基表呢?我使用的每个数据库都有一个整数序列表(通常是 100K 行),因为它通常非常有用。

【讨论】:

【参考方案5】:

CREATE TEMPORARY TABLE (ID int, Name char(100)) SELECT ....

阅读更多:http://dev.mysql.com/doc/refman/5.0/en/create-table.html

(靠近底部)

这样做的好处是,如果在填充表格时出现任何问题(数据类型不匹配),表格会被自动删除。

早期的答案使用了 FROM SELECT 子句。如果可能的话,使用它,因为它可以省去清理桌子的麻烦。

FROM SELECT 的缺点(可能无关紧要)是创建的数据集有多大。临时表允许进行可能很关键的索引。用于后续查询。似乎违反直觉,但即使是中等大小的数据集(约 1000 行),为查询操作创建索引也会更快。

【讨论】:

【参考方案6】:

在标准 SQL(SQL 2003 - 请参阅 http://savage.net.au/SQL/)中,您可以使用:

INSERT INTO SomeTable(Id, Count) VALUES (1, 7), (2, 6), (3, 13), ...

多追几下,还可以用:

SELECT * FROM TABLE(VALUES (1,7), (2, 6), (3, 13), ...) AS SomeTable(Id, Count)

这些在 MySQL 中的工作是否是一个单独的问题 - 但您总是可以要求添加它,或者自己添加它(这就是开源的美妙之处)。

【讨论】:

感谢您的回答!不幸的是 MySQL (5.0) 不喜欢 FROM TABLE(VALUES... 但至少我现在知道了 这个答案可能比接受的答案提供更多信息,它只是没有解决我的个人问题,因为我使用的是 MySQL。我希望我能接受多个答案。 相反,开源的丑陋之处在于,除非有很多人和/或有空闲时间的开发人员感兴趣,否则询问会被忽略或拒绝,而且 DIY 的学习曲线通常会让人望而却步。 (并不是说替代方案更好......) 删除关键字TABLE,这将适用于 MS SQL Server 2008 及以上版本。【参考方案7】:

我找到了这个链接Temporary Tables With MySQL

CREATE TEMPORARY TABLE TempTable ( ID int, Name char(100) ) TYPE=HEAP; 

INSERT INTO TempTable VALUES( 1, "Foo bar" ); 

SELECT * FROM TempTable; 

DROP TABLE TempTable;

【讨论】:

只是想知道这是否是 MySQL 的唯一答案。在与其他一些评论者相同的情况下,并且想知道除了临时表之外是否还有其他构造可以使用,例如列出内联数据的排序查询查询,但我想这仍然只是内存中的数据,与此示例相同.【参考方案8】:

我想你可以用几个SELECTs 结合UNIONs 来做一个子查询。

SELECT a, b, c, d
FROM (
    SELECT 1 AS a, 2 AS b, 3 AS c, 4 AS d
    UNION ALL 
    SELECT 5 , 6, 7, 8
) AS temp;

【讨论】:

哇,这是一个创造性的解决方案!听起来它至少会起作用。

以上是关于你能在 SQL 中定义“文字”表吗?的主要内容,如果未能解决你的问题,请参考以下文章

你能在 C++ 中保护嵌套类吗?

你能在 T-SQL 中对存储过程的结果进行选择吗

执行查询未定义

你能在文本中隐藏数据吗?

你能在 Zend 子表单中添加错误装饰器吗?

你能在 Rails 中获取数据库用户名、密码、数据库名称吗?