你能在 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】:我想你可以用几个SELECT
s 结合UNION
s 来做一个子查询。
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 中定义“文字”表吗?的主要内容,如果未能解决你的问题,请参考以下文章