【问题标题】:Can you define "literal" tables in SQL?你能在 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,但对其他可以做类似事情的数据库感兴趣。

【问题讨论】:

    标签: sql mysql subquery temp-tables


    【解决方案1】:

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

    请参阅文档:MariaDBMySQL

    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'关键字。

      见:

      【讨论】:

        【解决方案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;
            

            【讨论】:

            • 哇,这是一个创造性的解决方案!听起来它至少会起作用。
            猜你喜欢
            • 2014-10-11
            • 1970-01-01
            • 2015-09-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-22
            • 2011-04-30
            • 1970-01-01
            相关资源
            最近更新 更多