MySQL:从逗号分隔的列表/列表作为表格选择?“SELECT a FROM(1,2,3)”

7

有没有可能做到这样的事情(显然这种语法是不起作用的):

SELECT a FROM (1, 2, 3)

为了获得这个:
| a |
+---+
| 1 |
| 2 |
| 3 |

我希望从逗号分隔的列表中创建行,而不使用任何表格,或者至少不在数据库中创建表格(也许可以使用类似临时表的东西来实现?)。

也许可以通过使用其他SQL语句而不是select语句获取给定值的列?如果在MySQL中无法实现,但在其他SQL中可以实现,仍然很有趣。


1
@SashiKant 还有几千人也无法做到... - glglgl
4个回答

9
SELECT 1 a UNION ALL SELECT 2 a UNION ALL SELECT 3 a;

非常甜美,好主意,尽管陈述有点长 :) 但我相信你很可能会得到一个被接受的答案! :) - morphles
@aykut:因为您没有消除任何重复项,我建议使用UNION ALL而不是UNION - Arion
@morphles,你能给一个你想要的场景吗?我还没有理解你的问题 :/ - aykut
我正在使用一款应用程序,其中包含多种语言的文本,并且我们没有前端来输入某些文本。因此,我会像这样插入它们(默认情况下,所有语言的起始文本相同):INSERT INTO translations (name, translation, lang_id) SELECT 'somename','some_trans',id FROM languages。通过这样的选择,我应该能够添加连接并在一个查询中插入多个名称的翻译。不可否认,这是一个有点糟糕的用例,但我敢打赌,现在我有了这种方法,我会找到更有生产力的用途。不可否认,我自己无法想出解决方案有点失败 :) - morphles
你想用现有语言的文本填充所有缺失的翻译文本吗?这是一次性的工作吗?如果是,我认为你可以在应用层面完成它。 - aykut
@aykut:请阅读这篇文章,你就会明白我在指的是什么。我认为因为你不需要去重的值,所以应该使用UNION ALL而不是UNION语法。 - Arion

3

是否考虑使用临时表?我有一个建议,尽管需要多于1个查询:

-- DROP TEMPORARY TABLE tmp_list IF EXISTS;
CREATE TEMPORARY TABLE tmp_list (a INT);
INSERT INTO tmp_list (a) VALUES (1), (2), (3);
SELECT a FROM tmp_list;

2

如果MySQL不支持,但其他SQL支持,也很有意思。

在标准的SQL中,可以这样写:

select *
from ( values (1), (2), (3) ) t

这至少适用于PostgreSQL和DB2。

在PostgreSQL中,您可以通过扩展别名来为列命名(不确定列别名是否是SQL标准的一部分)。

select *
from ( values (1), (2), (3) ) t (id)

以下是使用公共表达式的替代方法。
with my_values (id) as (
  values (1), (2), (3)
)
select *
from my_values;

2

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

参见文档:MariaDBMySQL

MariaDB:

WITH mylist (a) AS (VALUES (1),(2),(3))
SELECT a FROM mylist

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

SELECT 1 AS a UNION ALL VALUES (2),(3)

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

VALUES (1),(2),(3) ORDER BY 1 DESC

实际的列名实际上就是值的第一行,所以你甚至可以这样做(虽然不太优雅,而且可能会遇到重复的列名错误):
SELECT `4` AS a FROM (VALUES (4),(5),(6)) mylist

MySQL:

我现在没有MySQL v8.0.19的实例可以测试,但根据文档 [编辑:在MySQL v8.0.23上使用dbfiddle.uk成功测试,参见评论#2中的链接] 以下任何一个都应该可以工作:

SELECT column_0 AS a FROM (VALUES ROW(1), ROW(2), ROW(3)) mylist

SELECT a FROM (VALUES ROW(1), ROW(2), ROW(3)) mylist(a)

与MariaDB不同,MySQL提供自动列名column_0、column_1、column_2等,并且在引用子查询时还支持重命名其所有列。
我不确定,但this dev worklog page似乎表明MySQL已经实现了(编辑:截至v8.0.26尚未实现)更短的语法(像MariaDB一样省略"ROW"),或者他们可能在不久的将来会这么做。

你提供的解决方案都没有在MySQL上起作用。 - dnetix
使用5.7.23 MySQL Community Server (GPL) 每个命令都响应“ERROR 1064 (42000):您的SQL语法中有一个错误; ...”解决方案是创建一个临时表来进行连接,这是一个较短的列表,原始列表有1000个bin需要检查CREATE TEMPORARY TABLE tmp_list (bin varchar(6)); INSERT INTO tmp_list (bin) VALUES ('365454'), ('360218'), ('360218'), ('364172'), ('364173'), ('364172'); SELECT bin, name FROM tmp_list LEFT JOIN provider_bin ON provider_bin.bine = tmp_list.bin WHERE provider_bin.bine IS NOT NULL; DROP TEMPORARY TABLE tmp_list; - dnetix
1
@dnetix 这个答案的第一行清楚地说明:“自MariaDB v10.3.3和MySQL v8.0.19以来,您现在可以做到...”。由于您仅使用MySQL的v5.7.23版本,因此该回答不适用于您的设置,因此您遇到的错误完全是可以预料的。当答案明确说明它不适用于您正在使用的MySQL版本时,请不要对其进行负面评价或发布误导性的普遍评论,例如“它不起作用”。 - Doin

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