簡體   English   中英

用awk替換sql列

[英]Replace sql column with awk

我在替換SQL腳本中的列時遇到問題。

我有這樣的數據(test.sql):

INSERT INTO TABLE
  (ID,TEXT)
VALUES
 (1,'TEXT');

INSERT INTO TABLE
 (ID,TEXT)
VALUES
  (2,'TEXT242');

INSERT INTO TABLE
 (ID,TEXT)
VALUES
(3,'TEXT424242');

我想用新值替換ID列上的“ TEXT”。 可以,我可以這樣做:

NEW="NEW"
grep 3 test.sql | awk -F "," -v OFS=, '{$2'$index'="'"'${NEW}'"'"; print }'

它將打印:

(3,'NEW');

所以,我有兩個問題:

  1. 我希望看到包括新行在內的所有行都進行如下更改:

     INSERT INTO TABLE (ID,TEXT) VALUES (1,'TEXT'); INSERT INTO TABLE (ID,TEXT) VALUES (2,'TEXT242'); INSERT INTO TABLE (ID,TEXT) VALUES (3,'NEW'); 
  2. 我想有一個完全匹配:所以3只有3而不是30 33 ...

可以這樣做,但是假設要替換的數據中沒有任何撇號,並且要匹配的id后面緊跟着一個逗號:

awk -F"'" -v id=3 -v newval="${NEW}" 'NF==3 { print $1 FS ($1 ~ id",$" ? newval:$2) FS $3 } NF!=3 {print $0}' test.sql

細分:

awk -F"'" -v id=3 -v newval="${NEW}" '

使用'作為分隔符,設置vars id和newval,其中newval來自bash

NF==3 { print $1 FS ($1 ~ id",$" ? newval:$2) FS $3 }

當有3個字段時,如果id匹配,則打印出現有的第二個字段或newval。

NF!=3 {print $0}' test.sql

打印所有其他行而不進行調整。

NEW="JIVE"輸出以下內容時:

INSERT INTO TABLE
  (ID,TEXT)
VALUES
 (30,'TEXT');

INSERT INTO TABLE
  (ID,TEXT)
VALUES
  (33,'TEXT242');

INSERT INTO TABLE
  (ID,TEXT)
VALUES
  (3,'JIVE');

在這里,我用30和33替換了原始ID 1和2,以證明它只是在修改您想要的行。


好吧,這變得更丑陋了,但這是一個新的“一個班輪”:

awk -F"'" -v id=3 -v newval="${NEW}" -v ind=$INDEX 'NF >= 2 {for(i=1;i<=NF;i++) {fld=($1 ~ id",$" && i==ind) ? newval : $i; printf("%s%s", fld, (i==NF ? "\n" : FS) ) }} NF < 2{print}' test.sql

細分:

awk -F"'" -v id=3 -v newval="${NEW}" -v ind=$INDEX '

除了其他變量之外,還添加了一個ind變量( index是保留的函數名)。 請注意,該指數是基於'字段分隔符。 在您的評論中, $index應該為6。

NF >= 2 {for(i=1;i<=NF;i++) {

超過兩個時,循環遍歷所有字段。

fld=($1 ~ id",$" && i==ind) ? newval : $i; 

根據ID和字段索引的匹配設置輸出字段。

printf("%s%s", fld, (i==NF ? "\n" : FS) ) }} 

打印出當前的字段和字段分隔符,將最后一個更改為換行符。

NF < 2{print}' test.sql

打印出所有剩余的行。

如果您只需要解決此特定問題(不需要完全解析語句,而且格式無變化),則sed可以實現一個更簡單的解決方案

更新 :OP已澄清它是第8列,應替換其值。

# Specify ID to match and replacement text.
id=3 new="NEW"

# Let `sed` perform the substitution. 
# `sed` outputs ALL lines by default, whether a substitution took place or not.
sed -E \
  "s/\($id(,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+,[^,]+),[^,]+(.*)/($id\1,'$new'\2/" \
  test.sql

如您所見,[^,]+為了捕獲中間的列值,[^,]+(...)中重復了6次-遺憾的是,使用{6}重復6次是不可行的,因為那樣只會捕獲模式的最后一個實例。


基於字段的awk解決方案:

更新 :OP已澄清它是第8列,應替換其值。

這種更靈活的解決方案使您也可以傳入目標列的從1開始的索引。 但是,假設ID列始終是first

awk -F '[,()]' -v id=3 -v ndx=8 -v new="'NEW'" '
  $2==id {
    $(ndx+1)=new # replace the column value
     # Row has been rebuilt with just spaces as separators
     # output it in the original format.
    printf " (%s", id
    for (i=3;i<NF;++i) printf ",%s", $i
    print ");"
    next 
  }
  { print }
  ' test.sql

請注意,不保留確切的前導空格。

另外請注意,由於輸入線路用字段分隔符開始( ), awk在開始創建一個額外的,空場;因此,指數加1。


重申一下警告:通常, awksed都不是解析SQL [DML]語句的正確工具。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM