创建一个包含 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 &lt; t1.name OR (t2.name = t1.name AND t2.id &lt;= 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 创建视图

Oracle PL/SQL 过程/函数来创建包含列的视图

如何创建一个包含 2 列的列表视图,显示所有已安装的 android 应用程序及其权限?

使用带有重复行和新列的 SQL Server 创建视图

HIVE:使用原始表中特定列的 n 值创建一个包含 n 列的新表

XML 数据类型列的视图