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

时间:2009-06-12 06:41:53

标签: sql mysql subquery temp-tables

是否有任何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,但对其他可以做类似事情的数据库感兴趣。

8 个答案:

答案 0 :(得分:51)

我想您可以使用多个SELECTUNION 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;

答案 1 :(得分:23)

你可以在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

答案 2 :(得分:18)

在标准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工作是否是一个单独的问题 - 但你总是可以要求添加它,或者自己添加它(这是开源之美)。

答案 3 :(得分:14)

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

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

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

请参阅:

答案 4 :(得分:6)

我找到了这个链接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;

答案 5 :(得分:1)

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

查看文档:{​​{3}}、MariaDB

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 等,并且还支持在引用时重命名子查询的所有列。

我不确定,但 MySQL 似乎表明 MySQL 也实现了较短的语法(省略了“ROW”,如 MariaDB),或者他们将在不久的将来实现。

答案 6 :(得分:0)

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行),也可以更快地为查询创建索引。

答案 7 :(得分:0)

总之,是的。如果您的SQL产品支持公共表表达式(CTE),即使用子查询加上相同的CTE,则可以多次使用,例如更好的IMO。这是为了在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列的字符。

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