每天把A表的数据写入到B表

本文介绍了一种使用Bash脚本实现的批量插入及更新MySQL数据库的方法。具体包括通过命令行执行SQL语句,利用条件判断来确定日期参数,并构造复杂的SQL语句以进行数据的批量处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#!/bin/bash
 source /etc/profile

if [ -z $1 ];
  then
  date=`date -d yesterday +"%Y-%m-%d"`
  else
  date=$1
 fi

 

echo "=================== ${date} start ==================="

 

#系统、服务器、动作都为全部的情况
sqlOne="
 INSERT INTO st_las_chart_ds
 (sdate,system,server,request,access_count,avg_duration,avg_response,system_tot_access_count,system_act_tot_access_count,system_avg_duration,system_avg_response)
 SELECT D1.sdate,'全部' AS system,'全部' server,'全部' AS request,0 AS access_count,0 AS avg_duration,0 AS avg_response,
  D1.tot_access_count AS system_tot_access_count,
  D1.act_tot_access_count AS system_act_tot_access_count,
  round(IFNULL(D1.tot_sum_duration/D1.tot_access_count,0),3) AS system_avg_duration,
         round(IFNULL(D1.tot_sum_response/D1.D1.tot_access_count,0),3) AS system_avg_response
 FROM(
 SELECT sdate,
  sum(sum_duration) tot_sum_duration,
  sum(CASE WHEN request LIKE '%.do' THEN sum_duration
  WHEN request LIKE '/rpc/%' THEN sum_duration
  WHEN request LIKE '/openrpc/%' THEN sum_duration
  WHEN request LIKE '/webservice/%' THEN sum_duration
  WHEN request LIKE '/ws/%' THEN sum_duration
  ELSE 0 END) act_tot_sum_duration,
         sum(sum_response) tot_sum_response,
  sum(access_count) tot_access_count,
  sum(CASE WHEN request LIKE '%.do' THEN access_count
  WHEN request LIKE '/rpc/%' THEN access_count
  WHEN request LIKE '/openrpc/%' THEN access_count
  WHEN request LIKE '/webservice/%' THEN access_count
  WHEN request LIKE '/ws/%' THEN access_count
  ELSE 0 END) act_tot_access_count
 FROM lasmyisam.st_las_request_ds
 WHERE sdate='${date}'
 GROUP BY sdate
 ) D1
 ON DUPLICATE KEY UPDATE
 access_count=values(access_count),
 avg_duration=values(avg_duration),
 avg_response=values(avg_response),
 system_tot_access_count=values(system_tot_access_count),
 system_act_tot_access_count=values(system_act_tot_access_count),
 system_avg_duration=values(system_avg_duration),
 system_avg_response=values(system_avg_response);"

 

mysql --host='test.com' -uroot -p123456789 -e "${sqlOne}" --default-character-set=utf8 testdb


echo "sqlOne: $sqlOne"

echo "===================DONE==================="

 

 

 

 

 

 

 

 

<think>我们有两个:A和B。需要根据B中的Price数据更新A中昨天Price为空的记录。 假设: - A和B都有一个可以关联的字段,比如商品ID(item_id)或订单ID(order_id)等。这里由于问题没有明确给出关联字段,我们假设关联字段为`item_id`。 - 更新条件:更新A中昨天(即业务日期为昨天)且Price为空的记录,用B中对应item_id的Price来更新。 步骤: 1. 确定更新日期:假设业务日期字段为`dt`,那么昨天的日期可以用`date_sub(current_date, 1)`示(这里使用Hive SQL的日期函数,如果是其他数据库,函数可能不同)。 2. 关联条件:A和B通过`item_id`关联。 3. 更新条件:A的`dt`为昨天,且A的Price为空(NULL),同时B在相同`item_id`下有非空的Price。 注意:由于引用[1]中提到全量存储和拉链存储,但这里更新操作是针对具体某一天(昨天)的数据,我们假设A是按天分区的,并且我们只更新昨天的分区。 根据上述分析,我们可以写出如下的SQL更新语句(以Hive SQL为例,因为引用中提到了分区,且是数据仓库常见的场景): 但是注意,Hive在较新版本才支持UPDATE(且需要配置事务支持),在数据仓库中更常见的做法是重写整个分区。但问题要求更新,所以这里提供两种方式: 方式1:使用Hive的UPDATE语句(如果支持的话): ```sql UPDATE A SET Price = B.Price FROM B WHERE A.dt = date_sub(current_date, 1) -- 只更新昨天的分区 AND A.Price IS NULL AND A.item_id = B.item_id AND B.Price IS NOT NULL; -- 确保B的价格不为空 ``` 方式2:如果数据量较大,且采用分区存储,更常见的做法是重写整个分区(即使用INSERT OVERWRITE重新写入昨天的分区)。但这样需要先准备好整个分区的数据,包括不需要更新的行。 重写分区的步骤: 1. 将A昨天分区的数据中,Price为空且B有对应记录的行,用B的Price替换;其他行保持不变。 2. 然后将整个分区的数据重新写入。 假设A有字段:item_id, Price, dt(分区字段) 那么重写分区的SQL可能如下: ```sql INSERT OVERWRITE TABLE A PARTITION (dt = date_sub(current_date, 1)) SELECT A.item_id, COALESCE(A.Price, B.Price) AS Price, -- 如果APrice为空,则用B的Price,否则用A自己的 -- ... 其他字段 FROM A LEFT JOIN B ON A.item_id = B.item_id WHERE A.dt = date_sub(current_date, 1); ``` 但是注意:上面的方法会覆盖整个分区的数据,而且使用了LEFT JOIN,如果A中一条记录在B中有多条,则会出现重复,导致数据错误。所以需要确保B的item_id是唯一的,或者使用聚合(如取最新的一个)。 更安全的做法是,先获取A昨天分区的所有数据,然后对于Price为空的记录,去B获取对应的Price(如果B有多个,则取一个,比如取最大的或最小的,根据业务决定)。这里假设我们取B最新的记录(假设B有日期字段,取最大的日期对应的Price),如果没有日期字段,则任意取一个(比如MAX或MIN)。 因此,我们可以这样写: ```sql -- 先创建临时数据:将A昨天分区的数据与B关联,并填充Price WITH temp_data AS ( SELECT A.item_id, COALESCE(A.Price, B.Price) AS Price, -- ... 其他字段 FROM A LEFT JOIN ( -- 对B按item_id去重,这里使用row_number()取每个item_id最新的一条(假设B有日期字段update_time) SELECT item_id, Price, ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY update_time DESC) as rn FROM B ) B ON A.item_id = B.item_id AND B.rn=1 WHERE A.dt = date_sub(current_date, 1) ) -- 然后覆盖写入A的昨天分区 INSERT OVERWRITE TABLE A PARTITION (dt = date_sub(current_date, 1)) SELECT * FROM temp_data; ``` 但是,如果A数据量很大,且我们只需要更新一部分记录,使用覆盖整个分区的方式可能效率较低。因此,在实际操作中,需要权衡。 另外,根据引用[2]提供的名,这里并没有直接提到A和B,所以具体名和字段需要根据实际情况调整。 考虑到问题描述中只提到了更新A中昨天Price为空的记录,且使用B的Price,我们假设关联字段是item_id,并且B中每个item_id只有一条记录(或者我们取一条)。 因此,如果系统支持UPDATE,且数据量不大,使用UPDATE是最直接的。如果不支持,则采用重写分区的方式。 根据引用[1]中提到的全量存储和拉链存储,如果A是全量存储(每天分区是全量快照),那么重写整个分区是合理的。如果是拉链存储,则更新操作需要修改start_dt和end_dt,比较复杂,但问题中只要求更新昨天的记录,而昨天分区的记录在拉链中可能还没有结束(即end_dt为未来一个很大的日期),所以需要更新拉链中的该条记录,并插入新的记录?这比较复杂,且问题没有说明是拉链,所以我们按照全量存储处理。 结论:根据问题的描述,我们采用全量存储的方式,使用重写分区的方法来更新数据。 但是,如果A不是分区,或者没有分区,那么只能使用UPDATE语句(如果支持)或者使用MERGE INTO语句(如果数据库支持)。 由于问题没有明确说明结构,我们假设是分区(按天分区),所以采用重写分区的方式。 注意:重写分区前,最好备份数据,以防出错。 因此,最终的解决方案(采用重写分区)如下: 步骤: 1. 创建一个临时视图,包含昨天分区的所有数据,并将其中Price为空的记录用B对应的Price填充(如果B有的话)。 2. 将临时视图的数据覆盖写入A的昨天分区。 具体SQL(Hive)如下: ```sql -- 设置分区 SET dt = date_sub(current_date, 1); -- 使用动态分区覆盖写入 INSERT OVERWRITE TABLE A PARTITION (dt = '${hiveconf:dt}') SELECT A.item_id, -- 如果A的Price为空,则用B的Price,否则保留A的Price CASE WHEN A.Price IS NULL THEN B.Price ELSE A.Price END AS Price, -- ... 其他字段 FROM A LEFT JOIN ( -- 对B按item_id去重,取每个item_id的一条记录(这里假设取Price不为空且最新的一条,如果没有时间字段,则取任意一条) SELECT item_id, Price FROM ( SELECT item_id, Price, ROW_NUMBER() OVER (PARTITION BY item_id ORDER BY update_time DESC) as rn FROM B WHERE Price IS NOT NULL -- 只取Price不为空的记录 ) t WHERE rn = 1 ) B ON A.item_id = B.item_id WHERE A.dt = '${hiveconf:dt}'; ``` 注意: - 这里使用了子查询对B去重,确保每个item_id只取一条记录(最新的一条)。 - 如果B没有时间字段,则无法按时间排序,可以去掉排序,这样取的是任意一条(但这样可能不符合业务,需要根据业务调整)。 - 如果B没有重复的item_id,则不需要去重。 如果B没有时间字段,且允许重复,那么我们可以使用聚合函数(如MAX或MIN)来取一条: ```sql SELECT item_id, MAX(Price) as Price -- 或者MIN(Price),根据业务决定 FROM B WHERE Price IS NOT NULL GROUP BY item_id ``` 这样也可以保证每个item_id只有一条记录。 因此,根据B的结构选择去重方式。 最后,由于问题中要求更新的是昨天Price为空的记录,所以我们在关联后,只更新了昨天分区的数据,并且只将Price为空的替换掉。其他记录保持不变。 请根据实际结构和业务需求调整SQL。 相关问题: 1. 在数据仓库中,更新历史数据有哪些常见的方式? 2. 全量存储和拉链存储各有什么优缺点? 3. 在Hive中执行覆盖分区操作需要注意哪些事项?</think>根据需求,您需要使用B中的Price数据更新A中昨天Price为空的记录。以下是分步解决方案: ### 1. **确定关联字段** 首先需要确认A和B之间的关联字段(如商品ID、订单ID等)。假设两通过`item_id`字段关联,且A有日期分区字段`dt`。 ### 2. **更新SQL语句(Hive语法示例)** ```sql INSERT OVERWRITE TABLE A PARTITION (dt = '${yesterday}') SELECT A.item_id, COALESCE(A.Price, B.Price) AS Price, -- 优先取BPrice A.other_columns -- 其他字段保留原值 FROM A LEFT JOIN B ON A.item_id = B.item_id WHERE A.dt = '${yesterday}' AND A.Price IS NULL; -- 仅处理空值记录 ``` ### 3. **关键逻辑说明** 1. **关联条件** `LEFT JOIN B ON A.item_id = B.item_id`:通过商品ID关联两[^2] 2. **空值替换** `COALESCE(A.Price, B.Price)`:当APrice为空时使用B值填充 3. **分区限定** `WHERE A.dt = '${yesterday}'`:仅更新昨天分区的数据(需替换为实际日期) 4. **覆盖写入** `INSERT OVERWRITE`:重写分区保证数据一致性[^1] ### 4. **注意事项** - **数据去重**:若B存在重复`item_id`,需先聚合处理(如`MAX(B.Price)`) - **性能优化**:对A分区裁剪(`dt='${yesterday}'`)可加速查询 - **空值保护**:添加`WHERE B.Price IS NOT NULL`避免引入新空值 - **业务验证**:更新后需确认消费者认可的价值一致性[^3] ### 5. **替代方案(UPDATE语法)** 若数据库支持事务更新: ```sql UPDATE A SET Price = B.Price FROM B WHERE A.item_id = B.item_id AND A.dt = '${yesterday}' AND A.Price IS NULL; ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值