Shell-Script

從 csv 文件中獲取數據並在數據庫中執行相關操作的腳本

  • July 14, 2016

我是 shell scripting 世界的新手,對 shell scripting 不太了解。我的工作要求我編寫一個腳本,該腳本從儲存在 CSV 文件中的記錄列表中獲取電話號碼。

對於每個電話號碼,它會在數據庫中的使用者表中進行搜尋,如果找到匹配項,則通過在電話號碼前添加“A2B1”來更新電話號碼列。

例如,如果在包含記錄的 csv 文件中找到類似“456789”的電話號碼在數據庫中的記錄,則電話號碼列將更新為“A2B1 456789”。

我想到了以下方法:首先,我將使用“cut”命令從 CSV 文件的每一行中取出第二列。(但是,我不知道,如何將每行第二列的值儲存在一個變數中,以便我可以在 SQL 查詢語句中使用它。)創建一個 db 連結,並編寫 SQL 搜尋語句/查詢.

然後,如果返回一些記錄,然後將完成上述更新。

我不知道如何執行此操作或用 shell 語言編寫它。我嘗試考慮一種將查詢的輸出傳送到文件並檢查文件大小是否為零的方法,如果不是,則使用文件中的變數(這是記錄/電話號碼)由查詢返回,然後將其儲存在變數中並執行更新操作,但我懷疑這將是一個好方法,而且考慮到我在這個領域的兩天嬰儿期,我對此沒有信心語法太。熱切期待您的幫助

您可以使用此腳本:

#!/bin/bash
PREFIX="A2B1 "
TABLE="sqltablename"
COLUMN="sqlcolumnname"
if [[ ! -r "$1" ]]; then
  echo "unable to read file '$1'"
  exit 1
fi

cut -d, -f2 "$1" | while read phonenum; do
  newnum="$PREFIX $phonenum"
  echo "UPDATE $TABLE SET $COLUMN = '$newnum' WHERE $COLUMN = '$phonenum';"
done

如果您使用 CSV 文件作為參數(例如./script.sh /path/to/mydata.csv)執行它,這將輸出一系列 SQL 語句,這些語句將按照您的描述更新數據。修改腳本以使用正確的表名和列名。

一旦您確認它為您提供了您想要的語句,您就可以將它通過管道傳輸到您選擇的 SQL 引擎中,或者將輸出保存到一個 SQL 文件中,您可以使用./script.sh /path/to/mydata.csv > /path/to/updatephonenumbers.sql.

雖然您可以在 shell 腳本中進行查詢/更新/等操作,但使用對數據庫和 CSV 文件都有良好支持的語言(如或)mysql要容易得多。perl``python

這是perl使用 perlDBI模組和DBD::CSVandDBD::mysql模組的一種方法。

它從您的 CSV 文件中讀取每一行(我將其稱為“updates.csv”並假設列名是),並為mysql中的數據庫表phonenum發出 SQLUPDATE命令。更改以適合您的數據庫。users``dbname``dbname

注意:以下程式碼未經測試,但應該可以工作。由於它未經測試,我可能犯了一些錯別字或其他錯誤。

強烈建議首先在數據庫的副本上對其進行測試,而不是立即在真實數據上執行它。事實上,在真實數據的副本上測試你的程式碼總是一個好主意,不管你在寫什麼或者你用什麼語言寫的。

#! /usr/bin/perl

use strict;
use DBI;

### 
### variables setup
### 

# DBD::CSV treats all .csv files in this dir as tables.
# i.e. this directory is the "database" and the .csv files
# are the tables in that database.
my $csv_dir = '/path/to/csv/dir'; 

my $csv_db  = 'updates';    # corresponds to "$csv_dir/updates.csv"

my $m_db    = 'dbname';     # replace with your mysql database name 
my $m_user  = 'username';
my $m_pass  = 'password';
my $m_host  = 'localhost';
my $m_port  = '3306';
my $m_dsn   = "DBI:mysql:database=${m_db};host=${m_host};port=${m_port}";

###
### database handle setup
###

# database handle for CSV connection
my $c_h = DBI->connect ("DBI:CSV:", undef, undef, {
              f_ext      => ".csv/r",
              f_dir => $csv_dir,
              RaiseError => 1,
              }) or die "Cannot connect: $DBI::errstr";


# database handle for mysql connection
my $m_h = DBI->connect($m_dsn, $m_user, $m_pass, { PrintError => 0 });

###
### all set up, time to do some work.
###

# NOTE: this script assumes that the .csv file contains a header line with
# the field names as the first line of the file.
#
# If not, the easiest thing to do is edit it with your preferred text
# editor and add one.  Otherwise, see `man DBD::CSV` to find out how to
# specify field names.
#
# or EDIT and uncomment the following three lines of code:

#$c_h->{csv_tables}{$csv_db} = { 
#  col_names => [ qw(column1 phonenum column3 column4 ...) ];
#};

# prepare statement handle for csv db query using a placeholder ? for the
# column name.
my $c_sth = $c_h->prepare("select phonenum from ?");

# and execute it.  later, we'll use a forech loop to read the data returned
$c_sth->execute($csv_db);

# prepare the SQL statement for the mysql db using placeholders ? for
# the values. this assumes that the column/field name is also called
# 'phonenum' in mysql.  These placeholders are invaluable, they automaticaly
# quote any data that needs to be quoted (e.g. strings) while not quoting
# things that shouldn't be quoted (e.g. integers).  They prevent a huge
# range of common mistakes.
#
# prepare it once, execute it multiple times with different values.

my $m_sth = $m_h->prepare('UPDATE users SET phonenum = ? WHERE phonenum = ?');

$m_h->begin_work;  # begin transaction

foreach ($c_sth->fetchrow_array) {
  chomp;
  my $newphone = "A2B1 $_";
  $m_sth = $m_sth->execute($newphone, $_);
};

$m_h->commit;  # commit transaction

### 
### we're done.  finish the statement handles and disconnect from
### the databases.
###
$c_sth->finish;
$m_sth->finish;
$c_h->disconnect;
$m_h->disconnect;

它看起來比一般的快速 shell 腳本更長,但大部分程式碼只是變數和數據庫句柄設置(並且該設置程式碼可以在其他類似的腳本中重複使用)。完成這項工作的實際程式碼(不包括註釋)只有大約六行左右。

引用自:https://unix.stackexchange.com/questions/295524