天道酬勤,学无止境

使用 fluentmigrator 用每行的新值更新行数据(Update row data with a new value per row using fluentmigrator)

问题

我正在使用 fluentmigrator 向表中添加一个新列。 然后,我想用该列的唯一值更新表中的每一行。

目前当我使用:

Update.Table("Foo").InSchema("dbo").Set(new { Bar = Bar.Generate() }).AllRows();

它为所有行提供相同的值。

如何确保它为每一行调用该方法?

回答1

我不确定 Bar.Generate 做了什么,但我猜它会创建一个 GUID 或唯一 ID。

如果是这样,那么您可以使用:

Execute.Sql("update dbo.Foo set Bar = NEWID()");

或者,如果您想要顺序 guid,那么您可以使用 NEWSEQUENTIALID()。

如果要为此唯一标识符添加新列,那么您需要做的就是指定新列 .AsGuid()

编辑:FluentMigrator 是一个小的流利的 dsl,并不意味着涵盖这样的复杂案例。 没有办法(据我所知)用一个 sql UPDATE 来做到这一点,因此用 FluentMigrator 也没有简单的方法来做到这一点。 您必须使用 ADO.NET 或 ORM(Dapper/NHibernate)获取表的行数,然后遍历每一行并使用自定义唯一标识符更新 Bar 列。 因此,如果您有一百万行,那么您将不得不进行一百万次 sql 更新。 如果您可以将 Bar.Generate() 方法重写为基于 NEWID() 函数的 Sql 函数,那么您可以将其作为一个 UPDATE 语句执行,并使用 FluentMigrator 的 Execute.Sql 方法调用它。

您还没有提到您正在使用哪个数据库。 但是像 Postgres 这样的一些非标准功能可以帮助您。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • PLSQL:NEW和:OLD(PLSQL :NEW and :OLD)
    问题 谁能帮助我了解何时在PLSQL块中使用:NEW和:OLD ,但我很难理解它们的用法。 回答1 通常,您在触发器中使用这些术语:old引用旧值,而:new引用新值。 这是上面链接的Oracle文档中的示例 CREATE OR REPLACE TRIGGER Print_salary_changes BEFORE DELETE OR INSERT OR UPDATE ON Emp_tab FOR EACH ROW WHEN (new.Empno > 0) DECLARE sal_diff number; BEGIN sal_diff := :new.sal - :old.sal; dbms_output.put('Old salary: ' || :old.sal); dbms_output.put(' New salary: ' || :new.sal); dbms_output.put_line(' Difference ' || sal_diff); END; 在这个例子中,触发器触发BEFORE DELETE OR INSERT OR UPDATE :old.sal将包含前触发器触发和薪水:new.sal将包含新的价值。 回答2 :DML语句中可以区分:New和:Old值。 插入- :旧= NULL :新=插入新值 Update- :Old =
  • 在具有300万行的PostgreSQL数据库上进行缓慢的简单更新查询(Slow simple update query on PostgreSQL database with 3 million rows)
    问题 我正在Postegres 8.4上具有约300万行的表上尝试一个简单的UPDATE table SET column1 = 0 ,但是要花很长时间才能完成。 它已经运行了十多分钟。 现在是我最后一次尝试。 在此之前,我尝试在该表上运行VACUUM和ANALYZE命令,并且还尝试创建一些索引(尽管我怀疑这种情况是否会有所不同),但似乎没有帮助。 还有其他想法吗? 谢谢,里卡多 更新: 这是表结构: CREATE TABLE myTable ( id bigserial NOT NULL, title text, description text, link text, "type" character varying(255), generalFreq real, generalWeight real, author_id bigint, status_id bigint, CONSTRAINT resources_pkey PRIMARY KEY (id), CONSTRAINT author_pkey FOREIGN KEY (author_id) REFERENCES users (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT c_unique_status_id UNIQUE
  • SQL迁移工具[关闭](SQL migration tool [closed])
    问题 关闭。 此问题不符合 Stack Overflow 准则。 它目前不接受答案。 想改善这个问题吗? 更新问题,使其成为 Stack Overflow 的主题。 4年前关闭。 改进这个问题 我想写一个SQL迁移工具。 该工具必须: 合并文件夹中的新脚本, 验证这些脚本的合并, 针对数据库运行这些脚本。 如果发生验证错误,则突出显示无效行。 如果脚本成功部署,我想将此信息与版本和其他相关信息一起保存在数据库中。 我可以用一些验证框架来做到这一点,或者我可以使用 nHibernate 吗? 回答1 这里的聚会有点晚了,但这是列表中的一个很好的补充:- FluentMigrator FluentMigrator 是一个用 C# 编写的 .NET 数据库迁移框架。 基本思想是您可以创建迁移,这些迁移只是从迁移基类派生的类,并具有附加到它们的唯一版本号的迁移属性。 执行 FluentMigrator 后,您告诉它要迁移到哪个版本,它会运行所有必要的迁移,以便将您的数据库升级到该版本。 除了前向迁移支持,FluentMigrator 还支持执行迁移的不同方式以及称为配置文件和执行任意 SQL 的选择性迁移。 回答2 不完全是你的要求,但我想我知道你想要实现什么。 http://code.google.com/p/migratordotnet/ http://ayende.com/Blog
  • SQL QUERY用先前已知值中的值替换行中的NULL值(SQL QUERY replace NULL value in a row with a value from the previous known value)
    问题 我有2栏 date number ---- ------ 1 3 2 NULL 3 5 4 NULL 5 NULL 6 2 ....... 我需要用新值替换NULL值,并采用日期列中前一个日期中最后一个已知值的值,例如:date = 2 number = 3,date 4和5 number = 5和5。出现NULL值随机地。 回答1 如果您使用的是Sql Server,则应该可以使用 DECLARE @Table TABLE( ID INT, Val INT ) INSERT INTO @Table (ID,Val) SELECT 1, 3 INSERT INTO @Table (ID,Val) SELECT 2, NULL INSERT INTO @Table (ID,Val) SELECT 3, 5 INSERT INTO @Table (ID,Val) SELECT 4, NULL INSERT INTO @Table (ID,Val) SELECT 5, NULL INSERT INTO @Table (ID,Val) SELECT 6, 2 SELECT *, ISNULL(Val, (SELECT TOP 1 Val FROM @Table WHERE ID < t.ID AND Val IS NOT NULL ORDER BY ID DESC)) FROM
  • 如果列中存在值,则按行检查并按行更新新列(Check row wise if value is present in column and update new column row wise)
    问题 在 R 中,如何检查每行中的任何值(例如 2、3 或 4)是否存在于三列中的任何一列中,然后在第四列中更改该行? 假设我有一个 df: A B C D 1 1 1 2 1 1 3 1 1 如果第 n 行(A 列或 B 列或 C 列)== 2 或 3 或 4 然后 D[1,]=1, else = 0,我想写(没有 for 循环) 基本上按行检查我的数字是否出现在三个特定列中的任何一个中,如果是,则用 1 更新第四列,如果不是 0。 谢谢, 回答1 以下是如何使用dplyr : library(dplyr) test <- data.frame(A = c(1, 2, 3), B = c(1, 1, 1), C = c(1, 1, 1)) testColumns <- c(2, 3, 4) # Values you want to flag 现在我们有了我们的数据框和一个带有我们想要在新列中标记的值的向量,让我们使用rowwise()告诉 R 查看数据框的每一行,然后组合使用mutate()来创建基于各种情况的新列D 。 我们使用case_when()指定测试用例,然后指定它们所需的值。 这是我们如何做到的: test <- test %>% rowwise() %>% # Look at test on a 'by row' basis' mutate(D = case
  • jqgrid 在移动行后获取网格中的行(jqgrid get rows in grid after move rows)
    问题 我有一个包含 3 列的网格,如下所示: col1 col2 col_sortorder AAAA 1000 1 AAAA 1002 2 AAAA 1003 3 我使用户可以使用鼠标更改网格中的排序器。 例如移动顶部的第二行,所以网格看起来像: col1 col2 col_sortorder AAAA 1002 2 AAAA 1000 1 AAAA 1003 3 我通过以下方式实现了这一目标: jQuery("#list").jqGrid('sortableRows'); jQuery("#list").bind('sortstop', function() { fun_sort(event) }); 现在我想用 col_sortorder 的新值更新我的数据库。 函数 fun_sort() 由 sortstop-event 正确触发。 我的目的只是从网格中读取所有数据并使用 forloop-index 作为 col_sortorder 的新值,但是当我使用以下方法读取网格时: var allRowsInGrid = $('#list').jqGrid('getGridParam','data'); for (i = 0 ; i <= allRowsInGrid.length -1; i++){ var col1 = allRowsInGrid[i].col1; var
  • 如何使用来自另一个数据帧的新值更新 pyspark 数据帧?(How to update a pyspark dataframe with new values from another dataframe?)
    问题 我有两个火花数据框: 数据框 A: |col_1 | col_2 | ... | col_n | |val_1 | val_2 | ... | val_n | 和数据框 B: |col_1 | col_2 | ... | col_m | |val_1 | val_2 | ... | val_m | 数据帧 B 可以包含来自数据帧 A 的重复行、更新行和新行。我想在 spark 中编写一个操作,我可以在其中创建一个包含来自数据帧 A 的行以及来自数据帧 B 的更新行和新行的新数据帧。 我首先创建了一个仅包含不可更新列的哈希列。 这是唯一标识。 所以假设col1和col2可以更改值(可以更新),但是col3,..,coln是唯一的。 我创建了一个哈希函数作为hash(col3,..,coln) : A=A.withColumn("hash", hash(*[col(colname) for colname in unique_cols_A])) B=B.withColumn("hash", hash(*[col(colname) for colname in unique_cols_B])) 现在我想写一些火花代码,基本上从 B 中选择散列不在 A 中的行(所以新行和更新的行) ,并将它们与来自 A 的行一起加入一个新的数据帧。我怎样才能实现这一点皮斯帕克? 编辑:数据框 B
  • 在 Shiny 中,使用来自用户输入的新值更新 DataTable(In Shiny, update DataTable with new values from user input)
    问题 我正在编写一个闪亮的应用程序,它有一个表(使用DT::renderDataTable ),用户可以从中选择一行。 但我希望用户也能够添加新行,如果他们想要的东西不在表中。 我正在使用输入控件供用户输入新数据,并且我有一个操作按钮,如果按下该按钮,应根据输入值在表中创建新的数据行。 但是按下按钮不会更新表格。 一个最小的例子: library(shiny) library(DT) mydata = data.frame(id=letters[1:5], val=sample(10,5,T)) ui = fluidPage(dataTableOutput("table"), textInput('NewID', 'Enter new ID'), numericInput('NewVal', 'Enter new val', 1), actionButton("goButton", "Update Table")) server = function(input,output){ output$table = renderDataTable(mydata) update = eventReactive(input$goButton, { newrow = data.frame(id = input$NewID, val = input$NewVal) mydata = rbind
  • 如何为列添加值并更新数据库(How To Add Value To A Column And Update Database)
    问题 我正在尝试将dataGridViewAFp1列Annual_Fees的值添加到我已转换为整数的文本框txtp1AF.Text中的新值AF2 。 然后将ResultAF 相加的结果转换回字符串updatedAF ,这是要在数据库中更新的值。 我确实将变量AF11初始化为 0。查询确实更新了选定的列。 这个想法是获取AF2 中的任何值,并将其添加到该列和行中的任何值,特别是我放入数据库中的AF11因此更新值updatedAF 。 这是我到目前为止所做的,但似乎没有用。 这些值没有相加。 private void btnEnterAFp1_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(txtp1AF.Text)) { MessageBox.Show("Please Enter fee","Oops",MessageBoxButtons.OK,MessageBoxIcon.Warning); } else { if (dataGridViewAFp1.Rows[0].Cells["Annual_Fees"].Value != null) { conn.Open(); SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; int
  • 如何使用R DBI传递data.frame以进行UPDATE(How to pass data.frame for UPDATE with R DBI)
    问题 使用RODBC,可以使用诸如sqlUpdate(channel, dat, ...)类的函数来传递dat = data.frame(...)而不必构造自己的SQL字符串。 但是,对于R的DBI,我所看到的只是dbSendQuery(conn, statement, ...)类的函数,该函数仅采用字符串statement而没有机会直接指定data.frame 。 那么如何使用带有DBI的data.frame进行UPDATE ? 回答1 我的回答真的来晚了,但也许还是有帮助的... DBI / odbc程序包中没有单个函数(我知道),但是您可以使用准备好的更新语句来复制更新行为(该更新语句的运行速度比RODBC的sqlUpdate快,因为它将批处理参数值发送到SQL Server: library(DBI) library(odbc) con <- dbConnect(odbc::odbc(), driver="{SQL Server Native Client 11.0}", server="dbserver.domain.com\\default,1234", Trusted_Connection = "yes", database = "test") # assumes Microsoft SQL Server dbWriteTable(con, "iris", iris
  • MySQL触发器分析
    触发器是一种特殊的存储过程,它在插入,删除或修改特定表中的数据时触发执行,它比数据库本身标准的功能有更精细和更复杂的数据控制能力。数据库触发器有以下的作用:1.安全性。可以基于数据库的值使用户具有操作数据库的某种权利。 # 可以基于时间限制用户的操作,例如不允许下班后和节假日修改数据库数据。 # 可以基于数据库中的数据限制用户的操作,例如不允许股票的价格的升幅一次超过10%。2.审计。可以跟踪用户对数据库的操作。 # 审计用户操作数据库的语句。 # 把用户对数据库的更新写入审计表。3.实现复杂的数据完整性规则 # 实现非标准的数据完整性检查和约束。触发器可产生比规则更为复杂的限制。与规则不同,触发器可以引用列或数据库对象。例如,触发器可回退任何企图吃进超过自己保证金的期货。 # 提供可变的缺省值。4.实现复杂的非标准的数据库相关完整性规则。触发器可以对数据库中相关的表进行连环更新。例如,在auths表author_code列上的删除触发器可导致相应删除在其它表中的与之匹配的行。 # 在修改或删除时级联修改或删除其它表中的与之匹配的行。 # 在修改或删除时把其它表中的与之匹配的行设成NULL值。 # 在修改或删除时把其它表中的与之匹配的行级联设成缺省值。 # 触发器能够拒绝或回退那些破坏相关完整性的变化,取消试图进行数据更新的事务。当插入一个与其主健不匹配的外部键时
  • mysql过程在更新前一行中的数字引用时进行更新(mysql procedure to update numeric reference in previous rows when one is updated)
    问题 有一张这样的桌子 ______________________ | id | title | order | |----------------------| | 1 | test1 | 1 | |-----|--------|-------| | 2 | test2 | 2 | |-----|--------|-------| | 3 | test3 | 3 | |-----|--------|-------| | 4 | test4 | 4 | '----------------------' 当我在mysql shell中引入对行的单个更新时 $sql> UPDATE `table` SET order=1 WHERE id=3; 然后过程或方法在更新较低的值之前重新采样顺序列中的订单列,以使其顺序更新 ______________________ | id | title | order | |----------------------| | 1 | test1 | 2 | |-----|--------|-------| | 2 | test2 | 3 | |-----|--------|-------| | 3 | test3 | 1 | |-----|--------|-------| | 4 | test4 | 4 | '------------------
  • SQL - 更新数据(UPDATE)
    本章,介绍如何利用UPDATE进一步操纵表数据。 更新数据 为了更新(修改)表中的数据,可以使用UPDATE语句。可采用两种方式使用UPDATE: 更新表中特定行。 更新表中所有行。 下面分别对它们进行介绍。 不要省略WHERE子句 在使用UDDATE时一定要注意细心。因为稍不注意,就会更新表中所有行。 UPDATE与安全 在客户机/服务器的DBMS中,可能需要特殊的安全权限。在你试图使用UPDATE前,应该保证自己有足够的权限。 基本的UPDATE语句由三部分组成,分别是: 要更新的表 列名和它们的新值 确定要更新哪些行的条件 举一个简单例子。客户1000000005现在有了电子邮件,因此它的记录需要更新,语句如下: UPDATE Customers SET cust_email = ‘kim@thetoystore.com’ WHERE cust_id = ‘1000000005’; UPDATE语句总是以要更新的表的名字开始。在此例子中,要更新的表的名字为Customers。SET命令用来将新值赋给被更新的列。如这里所示,SET子句设置cust_eamil列为指定的值: SET cust_email = ‘kim@thetoystore.com’ UPDATE语句以WHERE子句结束,它告诉DBMS更新哪一行。没有WHERE子句
  • 迁移器(FluentMigrator)的解释?(Explanation of Migrators (FluentMigrator)?)
    问题 有人可以解释一下 Migrators (特别是 fluentmigrator) 的概念吗? 以下是我收集到的(可能令人困惑的)事实: 它是一种通过版本控制最初创建然后维护数据库更新的方法。 第一次迁移(或数据库的初始版本)将包含所需的所有表、关系和属性(流畅地完成或在脚本中使用一段 sql 完成)。 当您想将更改推送到数据库时,您将创建一个新的迁移方法(向上和向下),例如添加新表或修改字段。 要部署这些迁移之一,您将使用命令行指定包含迁移、连接字符串和所需版本的 dll。 如果您有一组相当复杂的数据模型,为所有这些创建迁移定义是不是相当困难和耗时? 我知道使用 nHibernate/fluent 您可以轻松地为数据库生成表,而无需定义模型和映射文件以外的任何内容。 有没有办法使此配置与迁移器/版本控制兼容? 当 nhibernate/fluent 负责生成数据库时,我不一定需要定义表的每个方面。 它通过约定或通过映射文件完成。 对于迁移器,我需要定义这种详细程度吗? 回答1 这里有很多问题。 我将重点回答 FluentMigrator 的问题。 它是一种通过版本控制最初创建然后维护数据库更新的方法。 FluentMigrator 是一种版本控制数据库架构的方法。 每个人都以某种方式这样做。 手动,使用 sql 脚本,使用 SqlCompare 等工具或 Visual
  • 使用Python3自带GUI做个图形化操作SQLite3数据库的工具
    使用Python3自带GUI做个图形化操作SQLite3数据库的工具 #_*_ coding:utf8 _*_ ## Python3-GUI-DB-SQLite3 ## V1.6 import re from tkinter import * from tkinter import filedialog # 选择文件用 from tkinter import ttk # 下拉菜单控件在ttk中 import tkinter.messagebox # 弹出提示对话框 import tkinter.simpledialog # 弹出对话框,获取用户输入 import os # 导出文件要用到 import time # 导出文件要用到 import csv # CSV文件操作模块,用于导出数据 #from openpyxl import Workbook # Excel文件操作模块,用于导出数据(第三方模块,在需要时加载) import logging # 日志模块 Log = logging.getLogger('__name__') # 获取实例 formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s') # 指定logger输出格式 file_handler = logging
  • SQL - 如何更新每行值增加 1 的列?(SQL - how to update a column with each row value incremented by 1?)
    问题 对于列中选中的行,如何从头到尾依次更新每一行,每行值递增1(或某个数字)。 我知道这可以在几秒钟内在 excel 中完成,但我可以弄清楚如何在 SQL 服务器中实现。 例如: 客户 id 为 NULL 现在更新客户 id,每行加 1(即第一行 = 1,第二行 = 2,.....nth 行 = n) ship-to party customer id 0002018092 NULL 0002008127 NULL 0002000129 NULL 0002031592 NULL 0002034232 NULL 期望的输出 ship-to party customer id 0002018092 1 0002008127 2 0002000129 3 0002031592 4 0002034232 5 另外,对于列中选定的行,如何用行号更新每一行? 我知道有一个 row_number() 函数,但没有成功产生所需的结果。 例如 列 A 为 NULL 现在更新列 A,每行加 1(即第一行 = 行号 1,第二行 = 行号 2,.....n 第 n 行 = 行号 n) 任何演示都会非常有帮助。thkans 回答1 示例:假设我想为表tblUser SomeIntField列中的每个值添加一个值 有两种方法可以轻松做到这一点 第一:这只是将值 1 添加到每列 SomeIntField
  • 使用 openCSV 更新具有新值的行(Update a row with new values using openCSV)
    问题 我需要使用 openCSV 实用程序用新值更新一行。 例如,我有下面的 CSV 文件,我需要将包含TestdminUsername1和TestdminUsername2的行分别更新为TestdminUsername1,Fail,Errors Found和TestdminUsername2,Fail,Errors Found 。 TestdminUsername1,Pass,No Error TestAdminUsername2,Pass,No Error TestAdminUsername3,Pass,No Error TestAdminUsername4,Pass,No Error TestAdminUsername5,Pass,No Error TestAdminUsername6,Pass,No Error TestAdminUsername7,Pass,No Error TestAdminUsername8,Pass,No Error TestAdminUsername9,Pass,No Error TestAdminUsername10,Pass,No Error 以下是我正在使用的一段代码: import java.io.FileReader; import java.io.FileWriter; import java.util.Arrays; import
  • 使用自定义按钮进行引导选择并动态添加新值 [关闭](bootstrap-select with custom buttons & add new values on the fly [closed])
    问题 关闭。 这个问题是基于意见的。 它目前不接受答案。 想改善这个问题吗? 更新问题,以便通过编辑这篇文章用事实和引文来回答问题。 1 年前关闭。 改进这个问题 我需要使用可以执行该功能的下拉列表: 从数据库动态获取和加载值有一个嵌入式搜索框每个 Li 上有 2 个自定义按钮,一个用于删除,一个用于编辑。 搜索字段,如果搜索到的文本不存在,则在“输入”按下时添加它,或者在同一个选择<option> ,也可以在带有 Ajax 的数据库上添加。 我从 silviomoreto git 存储库中为 @twitter bootstrap 'bootstrap-select' 选择了自定义选择,因为我没有找到我想要的功能,所以我尝试自己制作。 所以,对于那些需要或想要在他们的 web 应用程序上添加该功能的人,我写下了我的解决方案,这不是最好的解决方案,但它有效,我愿意接受任何建议以使其更好地工作。 1. 步骤:创建一个带有参数的选择器: data-size="5"(显示 5 个值和添加滚动条),data-live-search="true"(在顶部添加搜索框)并加载值我从 db 得到(最好用 ajax): <select class="selectpicker typedropdown" data-size="5" data-live-search="true"> <?php
  • 插入、更新、删除的触发器(Trigger for insert, update, delete)
    问题 每当在主表“Table1”中发生插入、更新或删除时,我都想将行插入审计表 - 更改/插入哪一列无关紧要。 我还想在插入、更新或删除时添加 I、U 或 D。 对于插入和删除,我正在检查插入和删除的表中是否存在行。 接近更新的最佳方法是什么。 我的插入和删除代码是: CREATE TRIGGER [dbo].[tr_Table1_InsertUpdate_Table1History_Insert] ON [dbo].[Table1] FOR INSERT, DELETE, UPDATE AS BEGIN IF EXISTS(SELECT * FROM Inserted) BEGIN INSERT INTO Table1History(...., ModificationType) SELECT ..., 'I' FROM Inserted END IF EXISTS(SELECT * FROM Deleted) BEGIN INSERT INTO Table1History(..., ModificationType) SELECT ..., 'D' FROM Deleted END END GO 请帮助! 回答1 对于更新,该行的原始值将添加到已删除的表中,而该行的新值将添加到插入的表中。 因此,要识别插入、删除和更新,您将执行以下操作 插入 - 从插入中获取未删除的行删除 -
  • Tensorflow 更新每行中的第一个匹配元素(Tensorflow Update first matching element in each row)
    问题 基于这个问题,我希望在满足 tf.where 条件的情况下连续第一次更新二维张量的值。 这是我用来模拟的示例代码: tf.reset_default_graph() graph = tf.Graph() with graph.as_default(): val = "hello" new_val = "goodbye" matrix = tf.constant([["word","hello","hello"], ["word", "other", "hello"], ["hello", "hello","hello"], ["word", "word", "word"] ]) matching_indices = tf.where(tf.equal(matrix, val)) first_matching_idx = tf.segment_min(data = matching_indices[:, 1], segment_ids = matching_indices[:, 0]) sess = tf.InteractiveSession(graph=graph) print(sess.run(first_matching_idx)) 这将输出 [1, 2, 0] 其中 1 是第 1 行第一个 hello 的位置,2 是第 2 行第一个 hello 的位置,0 是第 3