news 2026/8/1 7:22:17

Pandas索引全解析:loc与iloc的核心区别、实战技巧与性能优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Pandas索引全解析:loc与iloc的核心区别、实战技巧与性能优化

1. 项目概述:从“查户口”到“按图索骥”的索引哲学

如果你用过Excel的VLOOKUP,或者写过一句SQL的SELECT * FROM table WHERE id=1,那你对“索引”这个概念就不会陌生。在数据处理的世界里,索引就是我们的导航仪和定位器。今天我们不聊数据库里那些B+树,就聊聊在Python数据分析的绝对主力——pandas里,两个最常用也最容易让人犯晕的索引函数:lociloc。这哥俩的名字就差一个字母,但用起来可是天差地别,一个像查户口本,一个像按门牌号找人。

简单来说,loc是基于“标签”的索引,你得知道你要找的那行数据或者那列数据,它叫什么名字(索引标签);而iloc是基于“位置”的索引,你只需要告诉它“我要第几行、第几列”,它就能给你扒拉出来,不管它叫张三还是李四。这个区别看似简单,但在实际处理数据时,用错了轻则报错,重则导致数据错位,得出完全错误的结论。比如你本想筛选“张三”的销售额,结果用iloc不小心定位到了“李四”那一行,这分析报告可就全乱套了。

这篇文章,我就以一个常年和脏数据、大表格打交道的过来人身份,掰开揉碎了给你讲清楚lociloc到底怎么用,它们背后的逻辑是什么,以及我在实战中踩过的那些坑和总结出的“骚操作”。无论你是刚入门pandas的新手,还是想重新梳理一下索引知识的老鸟,相信都能有所收获。我们直接从最核心的区别开始拆解。

2. 核心区别拆解:标签派 vs. 位置派

理解lociloc,关键在于抓住“标签”和“位置”这两个核心概念。这不仅仅是语法上的不同,更是两种截然不同的数据访问哲学。

2.1 本质区别:你认名字,还是认座位号?

想象一个教室,loc是班主任,他认识每个学生的名字(标签)。你想找“张三”,就直接喊“张三,出来一下”。iloc则是体育委员,他不管学生叫什么,只按学号或者座位表上的顺序来点名:“第一排第一个,出列!”

在pandas的DataFrame里:

  • 标签(Label):就是行索引(index)和列名(columns)。它们通常是字符串(如‘姓名’‘2023-Q1’),也可以是整数、时间戳等,但关键是,它们是这个数据项的“名字”。
  • 位置(Integer Location):就是纯粹从0开始的整数序号。第0行,第1列……它不关心这一行或这一列叫什么,只关心它在整个表格中的排列顺序。

让我们用代码创建一个简单的DataFrame来具象化这个区别:

import pandas as pd # 创建一个DataFrame,指定行索引(标签)为非连续的整数 data = { ‘姓名‘: [’张三‘, ’李四‘, ’王五‘, ’赵六‘], ‘年龄‘: [25, 30, 35, 28], ‘部门‘: [’技术部‘, ’市场部‘, ’技术部‘, ’财务部‘] } df = pd.DataFrame(data, index=[101, 102, 105, 108]) # 注意索引是101, 102, 105, 108 print(df)

输出会是:

姓名 年龄 部门 101 张三 25 技术部 102 李四 30 市场部 105 王五 35 技术部 108 赵六 28 财务部

现在,我们分别用lociloc来获取“李四”的信息:

  • 使用loc(按标签):我知道“李四”所在行的标签是102
    print(df.loc[102]) # 输出: 姓名 李四, 年龄 30, 部门 市场部
  • 使用iloc(按位置):我知道“李四”在从上往下数的第1行(因为从0开始计数)。
    print(df.iloc[1]) # 输出: 姓名 李四, 年龄 30, 部门 市场部

在这个例子里,两者结果一样。但玄机藏在索引里。我们的行索引是[101, 102, 105, 108],不是连续的0,1,2,3。如果我想要第3行(位置2)的数据:

  • df.iloc[2]会正确地返回索引为105,即“王五”的数据。
  • 如果你错误地使用了df.loc[2],pandas会直接给你抛出一个KeyError,因为它会在行索引里拼命找一个叫2的标签,但根本找不到。

注意:这是新手最容易栽跟头的地方。当你的DataFrame索引是默认的连续整数(0,1,2...)时,loc[1]iloc[1]结果巧合相同,这会给人一种“它们没区别”的错觉。一旦索引被重置、修改或者本来就是非数字,这个错觉就会立刻导致程序崩溃。

2.2 索引器的“含头含尾”规则

另一个重大区别在于切片操作。在Python原生的列表切片中,[start:stop]是“含头不含尾”的。但lociloc在这个规则上分道扬镳。

  • iloc:遵循Python传统,含头不含尾。df.iloc[1:3]选取的是位置为1和2的行(即第2、3行),不包含位置3。

  • loc:基于标签,含头且含尾。因为标签通常不是连续的整数,所以“含头含尾”更符合直觉。df.loc[102:105]选取的是行索引标签从102105的所有行。在我们的例子中,这会返回标签为102和105的两行(李四和王五)。它会把这两个标签以及它们之间的所有标签(如果存在的话)都包含进来。

这个规则在按日期时间索引时尤其重要。如果你想选取“2023-01-01”到“2023-01-31”整个月的数据,用loc[‘2023-01-01‘: ’2023-01-31‘]就能完美地包含首尾两天,非常直观。

2.3 布尔索引:共同的利器,不同的生成方式

两者都支持传入一个布尔序列(True/False组成的列表、Series或数组)来进行条件筛选。这是数据筛选中最强大的功能之一。但生成这个布尔序列时,你依然要遵循各自的规则。

# 筛选年龄大于28的员工 condition = df[’年龄‘] > 28 print(condition) # 输出: # 101 False # 102 True # 105 True # 108 False # 使用loc进行布尔索引 print(df.loc[condition]) # 正确,返回李四和王五 # 使用iloc进行布尔索引 print(df.iloc[condition.values]) # 需要将布尔Series转换为NumPy数组或列表,返回李四和王五

这里condition是一个索引对齐的布尔Series,loc可以直接使用。而iloc期望接收一个基于位置的布尔列表,所以通常需要.values来获取底层的数组。更常见的做法是,我们直接在loc里写条件表达式,更简洁:

# 更常见的loc布尔索引写法 print(df.loc[df[’年龄‘] > 28, [’姓名‘, ’部门‘]]) # 筛选行,并指定只查看’姓名‘和’部门‘列

3. 函数语法深度解析与实战演示

知道了核心区别,我们来深入看看它们的具体语法和能玩出的各种花样。你会发现,它们的灵活性远超你的想象。

3.1loc索引器:标签访问的完全指南

loc的通用语法是df.loc[行选择器, 列选择器]。两个选择器都可以是单值、列表、切片或布尔数组。

1. 单行单列(标量):

# 获取行标签为102,列名为’年龄‘的单个值 age_of_lisi = df.loc[102, ’年龄‘] # 返回 30

2. 多行多列(列表):

# 获取行标签为[102, 105],列名为[’姓名‘, ’部门‘]的数据,构成一个新的DataFrame subset = df.loc[[102, 105], [’姓名‘, ’部门‘]]

3. 行切片,列列表:

# 获取行标签从102到108(包含),列’姓名‘和’年龄‘的数据 # 注意:因为索引不连续,这里只包含102和108,105被跳过?不,loc切片会尝试匹配范围内的所有标签。 # 在我们的例子中,索引有102,105,108。所以df.loc[102:108]会返回102,105,108三行。 slice_result = df.loc[102:108, [’姓名‘, ’年龄‘]]

4. 条件筛选(布尔索引):这是loc最常用的场景。

# 单条件:部门是’技术部‘的员工 tech_emp = df.loc[df[’部门‘] == ’技术部‘] # 多条件:部门是’技术部‘且年龄大于30的员工 # 注意:每个条件要用括号括起来,逻辑运算符用 & (与), | (或), ~ (非) senior_tech = df.loc[(df[’部门‘] == ’技术部‘) & (df[’年龄‘] > 30)] # 复杂条件:使用`isin`函数 dept_list = [’技术部‘, ’市场部‘] emp_in_depts = df.loc[df[’部门‘].isin(dept_list)]

5. 赋值操作:loc不仅可以读,还可以写(赋值),这是修改DataFrame特定区域的推荐方式。

# 将李四(102)的部门改为’总裁办‘ df.loc[102, ’部门‘] = ’总裁办‘ # 将所有技术部员工的年龄增加1岁 df.loc[df[’部门‘] == ’技术部‘, ’年龄‘] += 1

实操心得:在对DataFrame进行修改时,始终优先使用lociloc进行显式索引赋值,避免使用df[‘部门‘][df[’年龄‘]>30] = ‘xx’这种链式赋值。链式赋值可能会触发SettingWithCopyWarning警告,因为其行为在某些情况下不确定。显式索引赋值(df.loc[…]=)是pandas官方推荐的安全做法。

3.2iloc索引器:位置访问的精准控制

iloc的语法与loc类似:df.iloc[行位置选择器, 列位置选择器]。所有选择器都是基于从0开始的整数位置。

1. 单行单列:

# 获取第2行(位置1),第1列(位置0)的值 value = df.iloc[1, 0] # 返回 ’李四‘

2. 多行多列:

# 获取第1,3行(位置0,2),第0,2列(位置0,2)的数据 subset = df.iloc[[0, 2], [0, 2]]

3. 行切片,列切片:

# 获取第2到第4行(位置1到3,不含3),所有列 rows_slice = df.iloc[1:3, :] # 返回李四和王五行 # 获取所有行,第1到最后一列(位置1到结束) cols_slice = df.iloc[:, 1:]

4. 使用负数索引:和Python列表一样,iloc支持负数索引,从末尾开始计数。

# 获取最后一行 last_row = df.iloc[-1] # 获取倒数两行,以及第0列和倒数第1列 last_two = df.iloc[-2:, [0, -1]]

5. 布尔索引(较少用):如前所述,需要将布尔Series转换为数组。

bool_mask = [False, True, True, False] # 一个基于位置的布尔列表 selected = df.iloc[bool_mask]

6. 赋值操作:同样支持。

# 将第0行第1列(张三的年龄)改为26 df.iloc[0, 1] = 26

3.3 混合场景与高级技巧

在实际项目中,数据访问需求往往更复杂。这里分享几个我常用的进阶模式。

场景一:我需要根据条件筛选行,但只修改其中某几列。这是loc的完美舞台。选择器可以非常灵活。

# 找到所有市场部的员工,将他们的年龄列设置为NaN(缺失值),并添加一个备注列 df.loc[df[’部门‘] == ’市场部‘, [’年龄‘, ’备注‘]] = [None, ’待核实‘] # 注意:这里赋值的是一个列表,会按顺序对应到筛选出的行的’年龄‘和’备注‘列。 # 如果’备注‘列不存在,pandas会自动创建它。

场景二:我想选取一个不连续的行列区域,但行列标识分别是标签和位置。lociloc本身不能混用,但我们可以通过一些方法间接实现。例如,我想用行标签筛选,但用列位置选取。

# 方法:先通过loc确定行,再通过列位置索引`.columns`属性获取列名,最后再用loc selected_rows = df.loc[[101, 105]] # 按标签选行 column_names = selected_rows.columns[[0, 2]] # 按位置[0,2]获取列名 result = selected_rows[column_names] # 通过列名选择 # 更简洁的写法(但可读性稍差): result = df.loc[[101, 105]].iloc[:, [0, 2]] # 注意:`.iloc`在这里作用于`df.loc[[101, 105]]`这个临时结果上。

场景三:处理多层索引(MultiIndex)的DataFrame。loc在处理多层索引时功能更强大,可以使用元组进行精确查询。

# 假设df有一个多层行索引:(年级, 班级) # 获取’高一‘年级,’3班‘的所有数据 df.loc[(’高一‘, ’3班‘), :] # 获取’高一‘年级所有班级的数据 df.loc[’高一‘, :] # 返回一个DataFrame # 使用`xs`方法也是处理多层索引的常用方式,但`loc`更直观。

对于iloc,它在多层索引中依然只认绝对位置,不关心标签层级,使用起来需要格外小心。

4. 性能考量与最佳实践选择

对于小型数据集,lociloc的性能差异可以忽略不计。但当数据量膨胀到百万、千万行时,选择正确的索引器就能省下宝贵的计算时间。

1.iloc通常更快:因为iloc直接映射到内存中的整数偏移量,操作类似于NumPy的数组索引,计算路径更短。loc则需要先在索引标签中进行哈希查找(如果索引是哈希able的)或二分查找(如果索引是排序的),找到对应的位置,然后再进行数据访问。多出的这一步查找,在大数据量下会有开销。

2. 何时用loc

  • 索引有业务含义时:当行/列索引是ID、日期、名称等具有业务意义的标签时,必须使用loc。代码df.loc[‘2023-12-01’]的可读性和可维护性远高于df.iloc[1234]
  • 进行条件筛选时df.loc[df[‘销量’] > 1000]是标准的、可读性高的筛选写法。虽然底层也涉及布尔数组,但用loc是惯例。
  • 使用切片且希望包含端点时:特别是时间序列数据。
  • 修改数据时:如前所述,使用loc赋值是避免SettingWithCopyWarning的安全做法。

3. 何时用iloc

  • 需要绝对位置时:例如,“取前10行”、“取每隔5行的数据”、“取最后5行”。df.iloc[:10]df.iloc[::5]df.iloc[-5:]
  • 在已知位置的循环或向量化操作中:如果你通过其他计算得到了一组确切的整数位置,用iloc访问更直接。
  • 索引是默认整数且你确定顺序不会变时:在数据清洗的中间步骤,如果索引是简单的range(N),且没有进行过会导致顺序混乱的操作(如sample),用iloc可能稍快且简洁。但要非常小心,一个不经意的reset_indexsort_values就可能让位置和标签的对应关系失效。

4. 一个重要的性能技巧:使用.at.iat获取/设置标量如果你只需要获取或设置一个单个单元格的值,使用.at(基于标签)和.iat(基于位置)会比lociloc快得多,因为它们是访问单个值的优化方法。

# 慢 value = df.loc[102, ’年龄‘] df.loc[102, ’年龄‘] = 31 # 快 value = df.at[102, ’年龄‘] df.at[102, ’年龄‘] = 31

避坑指南:在for循环中逐行修改DataFrame是性能杀手。如果非要这么做,务必使用.at.iat。但更好的做法是避免循环,尽量使用pandas的向量化操作或apply函数。

5. 常见错误与疑难问题排查

即使理解了原理,在实际编码时也难免会遇到各种报错和意外情况。下面我整理了一个常见问题速查表,并附上原因分析和解决方案。

问题现象可能原因解决方案
KeyError: [某个标签]使用loc时,传入的行或列标签在索引中不存在。1. 检查标签拼写、大小写、数据类型(如字符串‘101’和整数101不同)。
2. 使用df.index.isin([…])df.columns.isin([…])检查标签是否存在。
3. 如果允许标签不存在,考虑使用df.reindex()df.get(key, default)
IndexError: positional indexers are out-of-bounds使用iloc时,传入的整数位置超出了DataFrame的范围(例如,只有100行却请求iloc[100])。1. 检查DataFrame的形状:df.shape
2. 确保位置索引在0len(df)-1(行)或0len(df.columns)-1(列)之间。
3. 使用负数索引时,确保其绝对值不超过长度。
SettingWithCopyWarning通过链式索引(如df[‘a’][df[‘b’]>0] = 1)进行赋值,pandas无法判断是修改视图还是副本。永远使用单层的lociloc进行赋值df.loc[df[‘b’]>0, ‘a’] = 1。这是最根本的解决方法。
切片结果与预期行数不符混淆了loc(含头含尾)和iloc(含头不含尾)的切片规则,或者在非单调索引上使用loc切片。1. 明确你的意图:是按标签切还是按位置切?
2. 对于loc,确保索引是排序的(df.index.is_monotonic_increasing),否则切片行为可能奇怪。必要时先sort_index()
布尔索引返回空结果条件表达式可能产生了全为False的布尔序列。常见于条件逻辑错误或数据类型不匹配(如与字符串比较时误用数值)。1. 单独打印检查你的布尔条件:print(df[‘age’] > 30)
2. 检查数据类型:df[‘column’].dtype。可能需要先使用pd.to_numericastype转换类型。
3. 注意&, `
使用iloc后数据顺序错乱iloc中使用了整数列表,但这个列表不是顺序的,例如df.iloc[[2, 0, 1]]。这是正常功能,它会按照你给定的位置列表顺序返回数据。如果这不是你想要的,请检查你的位置列表。如果你想按原顺序筛选特定行,应使用排序后的列表或切片。
在多线程或异步环境中索引失效在数据被其他操作修改(如追加行、删除列)的同时进行索引操作,可能导致索引错位。确保在对DataFrame进行结构性修改(改变shape)的操作之间,索引访问是同步的。或者,在敏感操作前使用.copy()获取数据的副本进行操作。

一个经典的复合坑案例:假设你从一个CSV读取数据,它有一个“ID”列,你将其设为索引。

df = pd.read_csv(‘data.csv’, index_col=‘ID’) # 后来你过滤了一些行 df_filtered = df[df[‘value’] > 100] # 此时df_filtered的索引是原df索引的一个子集,可能不再是连续的整数。 # 如果你习惯性地想取“第一行”: first_row_wrong = df_filtered.iloc[0] # 这没问题,取位置0 # 但如果你想取ID为某个值的行: try: row_by_id = df_filtered.loc[0] # 可能报KeyError!因为ID=0的行可能已经被过滤掉了。 except KeyError as e: print(f“KeyError: {e}“)

教训:永远清楚你当前操作的DataFrame的索引状态。在链式操作后,使用df.index查看索引,再决定用loc还是iloc

6. 融会贯通:在真实数据流中的应用策略

理解了单个函数,最终我们要把它们融入到完整的数据处理流程中。下面我以一个模拟的电商订单数据分析小流程,展示lociloc如何各司其职。

假设我们有一个订单DataFrameorders:

import pandas as pd import numpy as np # 生成模拟数据 np.random.seed(42) dates = pd.date_range(‘2023-01-01’, periods=100, freq=‘D’) order_ids = range(1000, 1100) customer_ids = np.random.choice([‘C001’, ‘C002’, ‘C003’, ‘C004’, ‘C005’], 100) amounts = np.random.uniform(10, 500, 100).round(2) categories = np.random.choice([‘Electronics’, ‘Clothing’, ‘Books’, ‘Home’], 100) orders = pd.DataFrame({ ‘order_date’: dates, ‘customer_id’: customer_ids, ‘order_amount’: amounts, ‘category’: categories }) orders.index = order_ids # 将订单号设为索引 print(orders.head())

步骤1:数据概览与清洗(多用iloc和条件loc

# 1. 查看前5行数据(按位置,iloc) print(orders.iloc[:5]) # 2. 发现异常值:假设金额小于1的记录为异常 # 使用loc进行布尔索引查找和标记 orders[‘is_abnormal’] = False # 新增标记列 orders.loc[orders[‘order_amount’] < 1, ‘is_abnormal’] = True abnormal_count = orders[‘is_abnormal’].sum() print(f“异常订单数: {abnormal_count}“) # 3. 处理异常值:这里我们选择删除(实际中可能是修正或填充) # 使用loc获取正常数据,注意这里是通过布尔索引选择行 orders_clean = orders.loc[~orders[‘is_abnormal’]].copy() # 或者直接使用drop # orders.drop(orders.loc[orders[‘is_abnormal’]].index, inplace=True)

步骤2:切片分析与聚合(loc按标签/条件,iloc按位置)

# 1. 分析2023年1月上半月的数据(按日期标签切片) # 假设日期列已设置为索引,如果没有,需要先set_index # orders.set_index(‘order_date’, inplace=True) jan_first_half = orders.loc[‘2023-01-01‘: ’2023-01-15‘] # 含头含尾 print(f“1月上半月订单数: {len(jan_first_half)}“) # 2. 查看金额最高的前10笔订单(按位置,iloc) # 先按金额降序排序 top_orders = orders.sort_values(by=‘order_amount’, ascending=False).iloc[:10] print(“金额Top10订单:“) print(top_orders[[‘customer_id’, ‘order_amount’, ‘category’]]) # 用列名列表选择显示的列 # 3. 计算每个客户在电子品类上的总消费(loc条件筛选 + groupby) electronics_spend = orders.loc[orders[‘category’] == ‘Electronics’].groupby(‘customer_id’)[‘order_amount’].sum() print(“\n客户电子产品消费:“) print(electronics_spend)

步骤3:数据抽取与导出(灵活运用)

# 1. 随机抽取5%的订单进行审计(按位置,iloc配合随机抽样) sample_indices = np.random.choice(orders_clean.shape[0], size=int(orders_clean.shape[0]*0.05), replace=False) audit_sample = orders_clean.iloc[sample_indices] print(“审计样本:“, audit_sample.shape) # 2. 导出特定客户C003的所有订单(按标签,loc) customer_c003_orders = orders_clean.loc[orders_clean[‘customer_id’] == ‘C003’] # 可以保存到文件 # customer_c003_orders.to_csv(‘customer_C003_orders.csv’) # 3. 获取最后20条订单的ID和金额(按位置,iloc负数切片) recent_orders_info = orders_clean.iloc[-20:, [orders_clean.columns.get_loc(‘order_date’), orders_clean.columns.get_loc(‘order_amount’)]] # .get_loc(‘col_name’) 可以获取列名的整数位置,这样代码更健壮,即使列顺序变化也不怕。

在整个流程中,lociloc扮演了不同的角色:loc像是一个业务查询员,根据具体的业务标签(日期、客户ID、品类)和条件来精准抓取数据;而iloc更像是一个流水线操作工,按照固定的顺序和位置进行批量处理、抽样和查看。将它们结合使用,你就能像手术刀一样精准,又像流水线一样高效地处理数据。

说到底,lociloc的区别,是pandas设计哲学的一个缩影:它既提供了基于标签的高层、语义化的数据访问方式(贴近SQL和人类思维),也提供了基于位置的底层、高效的数据操作方式(贴近NumPy和数组计算)。掌握它们,不仅仅是记住语法,更是理解何时该用“名字”找人,何时该用“编号”点兵。当你能够根据具体场景下意识地选出合适的工具时,你就真正驾驭了pandas数据访问的核心。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/1 7:20:35

百度网盘提取码终极解决方案:如何一键秒速获取分享资源

百度网盘提取码终极解决方案&#xff1a;如何一键秒速获取分享资源 【免费下载链接】baidupankey 在线查询网盘提取码&#xff08;维护中 rm repo&#xff09; 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 还在为百度网盘提取码而烦恼吗&#xff1f;每次看…

作者头像 李华
网站建设 2026/8/1 7:16:43

Matplotlib图形生命周期管理:show、close与draw函数深度解析

1. 图形显示与关闭&#xff1a;不只是“画出来”那么简单很多刚开始用matplotlib的朋友&#xff0c;尤其是从Jupyter Notebook这类交互式环境入门的&#xff0c;可能会觉得画图就是plt.plot()然后图形就自动出来了。但当你开始写脚本、构建GUI应用&#xff0c;或者需要批量生成…

作者头像 李华
网站建设 2026/8/1 7:09:10

Python+Django+Vue3构建美食城数字化系统实践

1. 项目背景与核心价值在餐饮行业数字化转型浪潮中&#xff0c;中小型美食城面临三个典型痛点&#xff1a;商户管理分散、订单处理低效、数据统计滞后。我们团队为某地标美食街开发的这套系统&#xff0c;用PythonDjango处理复杂业务逻辑&#xff0c;配合Vue3构建现代化前端&am…

作者头像 李华
网站建设 2026/8/1 7:02:19

Android 10+开机自启动实现:从BOOT_COMPLETED广播到前台服务适配

1. 开机自启动的“旧梦”与“新规”在Android开发的漫长岁月里&#xff0c;让一个应用在设备开机后自动运行&#xff0c;曾经是件相当“直白”的事情。很多开发者&#xff0c;尤其是需要后台常驻服务的工具类、安全类应用的开发者&#xff0c;对此功能再熟悉不过。其核心原理&a…

作者头像 李华
网站建设 2026/8/1 6:58:35

4.从零搭建 SAP 标准 ALV 报表!Open SQL 多表关联、Fieldcat 手动构建、斑马纹布局全流程

摘要 SAP系统作为企业资源计划领域的标杆,其底层开发语言ABAP是每一位SAP技术人员的必修课。本文从SAP系统架构出发,深入解析ABAP程序的核心运行机制,涵盖数据字典对象、Open SQL、内表操作、模块化编程等关键知识点。通过一个完整的采购订单报表开发案例,串联从数据库读取…

作者头像 李华