创建一个包含 num_rows 列的视图 - MySQL
Posted
技术标签:
【中文标题】创建一个包含 num_rows 列的视图 - MySQL【英文标题】:Create a view with column num_rows - MySQL 【发布时间】:2013-04-09 01:52:04 【问题描述】:我需要创建一个视图,其中包含一个名为 row_num 的列,它将在其中插入行号,就像普通表中的自动增量一样。
假设我有这张普通的桌子:
| country | name | age | price |
--------------------------------
| US | john | 22 | 20 |
| France | Anne | 10 | 15 |
| Sweden | Alex | 49 | 10 |
等等……
我要创建的视图是:
| country | name | price | row_num |
------------------------------------
| US | john | 20 | 1 |
| France | Anne | 10 | 2 |
| Sweden | Alex | 5 | 3 |
等等……
我可以通过一次选择生成 row_num:
SELECT @i:=@i+1 AS row_num, testing.country, testing.name, testing.price
FROM testing testing,(SELECT @i:=0) derivedTable
order by name
但我的问题是将上面的查询与创建视图的查询结合起来。 这是我正在尝试的组合查询:
CREATE OR REPLACE view vwx (country, name, price, num_row) AS SELECT mytable.country, mytable.name, mytable.price, @i:=@i+1 AS row_number
FROM testing testing,(SELECT @i:=0) derivedTable
order by name;
我收到以下错误:#1351 - 视图的 SELECT 包含变量或参数
我知道我不能在带有视图的选择中使用选择,但我没有看到其他方法可以按照我想要的方式执行此视图,但我确信有办法做到这一点,但我只是不这样做不知道怎么做。可能是函数或过程,但我对它们真的很陌生,所以我不习惯在 mysql 中创建函数或过程。
我希望我说清楚了,否则我很乐意更详细地解释自己。
【问题讨论】:
为什么没有像“普通表”这样可以使用的自动增量? 因为我没有设计那个表,而且那个表已经存储了成千上万条记录。另外,他们不允许我更改该表上的任何内容,这就是我使用视图的原因。 啊,还有一个我忘了提到的@Neal 细节是视图是使用 where 子句创建的,我没有把它放在那里,因为我认为这不是一个重要的细节。 @dwnz 有办法做到这一点,但是您需要按记录排序的列应该是唯一的。 @Devart 你能告诉我怎么做吗?我会尽量让它适应我的问题。谢谢。 【参考方案1】:我找到了解决方案:
首先创建一个函数:
delimiter //
CREATE FUNCTION `func_inc_var_session`() RETURNS int
NO SQL
NOT DETERMINISTIC
begin
SET @var := @var + 1;
return @var;
end
//
delimiter ;
然后将@var 设置为您要开始的数字。 在这种情况下为零。
SET @var=0;
然后创建如下视图:
CREATE OR REPLACE VIEW myview (place, name, hour, price, counter)
AS SELECT place, name, hour, price, func_inc_var_session()
FROM yourtable
WHERE input_conditions_here;
这里的技巧是您可能会在 counter 列上看到 NULL。如果发生这种情况,请再次将 @var 设置为您的号码,然后再次执行 SELECT *,您将看到计数器列正确填充。
【讨论】:
当我这样做时,在“input_conditions_here”中使用“order by”,我得到 func_inc_var_session() 的顺序错误。我认为这里需要一个子查询。【参考方案2】:我尝试了func_inc_var_session
函数的例子。
我使用mysql IFNULL
函数解决了一个会话变量初始化的小问题。
下面是增强的func_inc_var_session
函数。
CREATE DEFINER=`root`@`localhost` FUNCTION `func_inc_var_session`() RETURNS int(11)
begin
SET @var := IFNULL(@var,0) + 1;
return @var;
end
【讨论】:
请注意:如果您在单个查询中使用该函数两次或多次(例如使用JOIN),它将继续增加变量。【参考方案3】:使用@dazito 的解决方案时,您可能会遇到计数器在查询之间不断增加的问题,例如,当您的应用程序重用会话时,例如使用 JPA / Hibernate。例如:
查询 1:
|国家 |姓名 |价格 |行数 | ---------------------------------- |美国 |约翰 | 20 | 1 | |法国 |安妮 | 10 | 2 | |瑞典 |亚历克斯 | 5 | 3 |查询 2:
|国家 |姓名 |价格 |行数 | ---------------------------------- |美国 |约翰 | 20 | 4 | |法国 |安妮 | 10 | 5 | |瑞典 |亚历克斯 | 5 | 6 |等等
对此的一种解决方案是将主查询与对计数器函数的(一次性)调用相结合,并参数化该函数(下面的“reset”参数)以使其知道这是第一次调用。
分隔符 // CREATE FUNCTION `func_inc_var_session`(reset BIT) RETURNS int 没有 SQL 不确定的 开始 IF 重置 THEN SET @var := 0; 别的 SET @var := IFNULL(@var,0) + 1; 万一; 返回@var; 结尾 // 分隔符;现在您可以在视图查询中调用该函数,将 reset 参数设置为 1 将函数的计数器变量设置回 0,并使用 0 递增计数器。该函数在加入时只会以 1 作为参数调用一次,如下所示:
创建或替换视图 country_view(国家、名称、价格、row_num) AS SELECT 国家、名称、价格、func_inc_var_session(0) 来自国家 加入 (SELECT func_inc_var_session(1)) r现在您每次都可以保证第 1、2、3 行。
【讨论】:
MySQL 不允许 VIEW 中的子查询。选择将独立工作,但不会创建视图。错误:#1349 - 视图的 SELECT 在 FROM 子句中包含子查询。 VIEW中的子查询限制适用于MySQL 5.7.7及以下版本。【参考方案4】:或者试试这个->创建一个临时表,然后像下面这样插入你的数据
CREATE OR REPLACE TEMPORARY TABLE myview (
country VARCHAR(250),
name VARCHA(50),
price VARCHAR(50),
row_num int(11)
);
SET @row_num = 0;
INSERT INTO myview (country,name,price,row_num)
SELECT @row_num:=@row_num+1
as country,name,price,row_num
FROM testing;
SELECT * FROM myview;
+---------+------+------+-------+---------+
| country | name | age | price | row_num |
+---------+------+------+-------+---------+
| Sweden | Alex | 49 | 10 | 1 |
| France | Anne | 10 | 15 | 2 |
| France | Anne | 11 | 16 | 3 |
| US | john | 22 | 20 | 4 |
+---------+------+------+-------+---------+
【讨论】:
【参考方案5】:尝试将此查询应用于您的视图 -
CREATE TABLE testing (
id int(11) NOT NULL DEFAULT 0,
country varchar(255) DEFAULT NULL,
name varchar(255) DEFAULT NULL,
age int(11) DEFAULT NULL,
price int(11) DEFAULT NULL,
PRIMARY KEY (id)
);
INSERT INTO testing(id, country, name, age, price) VALUES
(1, 'US', 'john', 22, 20),
(2, 'France', 'Anne', 10, 15),
(3, 'Sweden', 'Alex', 49, 10),
(4, 'France', 'Anne', 11, 16);
SELECT
t1.*, COUNT(*) row_num
FROM testing t1
LEFT JOIN testing t2
ON t2.name < t1.name OR (t2.name = t1.name AND t2.id <= t1.id)
GROUP BY t1.name, t1.id;
+----+---------+------+------+-------+---------+
| id | country | name | age | price | row_num |
+----+---------+------+------+-------+---------+
| 3 | Sweden | Alex | 49 | 10 | 1 |
| 2 | France | Anne | 10 | 15 | 2 |
| 4 | France | Anne | 11 | 16 | 3 |
| 1 | US | john | 22 | 20 | 4 |
+----+---------+------+------+-------+---------+
此查询不使用任何用户变量,因此它在视图中起作用。
ON 子句中的附加条件有助于在name
字段中实现重复值。
【讨论】:
在你的第 5 行,你有ON t2.name < t1.name OR (t2.name = t1.name AND t2.id <= t1.id)
t1.id 和 t2.id 到底是什么?我之所以问,是因为我没有 id 列,而且我不确定在我的情况下指的是什么。
哦,对不起。我的意思是唯一 ID 列。我将添加完整的示例。【参考方案6】:
MySql 从 8.0 版本开始支持函数ROW_NUMBER()
,它允许你创建一个视图。旧方法的问题(这是对所需行为的模拟)是在创建视图的那一刻,(@row_number:=@row_number + 1)
中的 @
混淆了视图创建的语法并抛出了 #1351 错误。
CREATE OR REPLACE view vwx (country, name, price, num_row) AS
SELECT
country,
name,
price,
ROW_NUMBER() OVER (ORDER BY final_score) row_num
FROM
testing
ORDER BY
name
【讨论】:
【参考方案7】:CREATE OR REPLACE view vwx (country, name, price, num_row) AS
SELECT country, name, price, @index := @index + 1 AS num_row
FROM testing, (SELECT @index := 0) temp
【讨论】:
这是不可能的,因为它在创建视图上使用了一个变量,我得到了和以前一样的错误:Error Code: 1351. View's SELECT contains a variable or parameter 0.000 sec
【参考方案8】:
在查询结果中添加行号 - 无需查看 - 一次查询
SELECT country, name, price, @ID := @ID + 1 AS row_num
FROM testing,
(SELECT @ID := 0) temp
将以下内容添加到您的 MySQL 连接字符串中:Allow User Variables=True;
请勿在查询中添加“交叉连接”来更新您的 @ID 变量。
注意:尝试在视图中使用它会导致:View's SELECT contains a variable or parameter
【讨论】:
欢迎来到 SO。正确格式化答案中的代码非常有帮助:-) OP 想要将结果作为视图,而您的答案将无法作为视图。以上是关于创建一个包含 num_rows 列的视图 - MySQL的主要内容,如果未能解决你的问题,请参考以下文章
需要从不包含隐藏 graph_id 列的 SQL Server Graph Table 创建视图
如何创建一个包含 2 列的列表视图,显示所有已安装的 android 应用程序及其权限?