2013-03-25 66 views
1

我一直在尋找,但到目前爲止,我只發現如何基於csv文件插入日期到表中。基於txt文件更新表格行

我有以下情形:

目錄名稱= ticketID

這個目錄我有幾個文件,如內幕:

  • Description.txt
  • Summary.txt - 包含票頭和已成功導入。
  • Progress_#.txt - 這是每次都有機票獲得udpdated。我得到一個新文件。
  • Solution.txt

導入Issue.txt很簡單,因爲這實際上是一個CSV。

現在我的問題是與描述和進度文件。

我需要使用此文件中的數據更新現有行。在

update table_ticket set table_ticket.description = Description.txt where ticket_number = directoryname 

我使用PostgreSQL的線和COPY命令一些適用於新的數據,它仍然會失敗是由於」; /特殊字符。

我想做到這一點使用bash腳本,但似乎它都將是不可能的:

for i in `find . -type d` 
do 
    update table_ticket 
    set table_ticket.description = $i/Description.txt 
    where ticket_number = $i 
done 

當然上面的代碼將考慮到數據庫的連接。

任何人都有一個想法,我可以如何實現這個使用shell腳本。或者,在Java中創建一些東西並閱讀和更新記錄會更好,儘管我想避免這種方法。

感謝 亞歷克斯

回答

4

感謝您的回答,但我碰到這個傳來:

psql -U dbuser -h dbhost db 
\set content = `cat PATH/Description.txt` 
update table_ticket set description = :'content' where ticketnr = TICKETNR; 

把這個變成一個簡單的腳本我創建了以下內容:

#!/bin/bash 
for i in `find . -type d|grep ^./CS` 
do 
    p=`echo $i|cut -b3-12 -` 
    echo $p 
    sed s/PATH/${p}/g cmd.sql > cmd.tmp.sql 
    ticketnr=`echo $p|cut -b5-10 -` 
    sed -i s/TICKETNR/${ticketnr}/g cmd.tmp.sql 
    cat cmd.tmp.sql 
    psql -U supportAdmin -h localhost supportdb -f cmd.tmp.sql 
done 

的缺點是,它總是會創建一個新的連接,稍後我將更改爲創建單個文件

但它確實如我所期待的那樣將內容放入單個列中。

+0

很好,謝謝。我不知道'\ set'中'psql'支持的反引號命令調用。這很方便,儘管我重複了我的建議,不再試圖在shell和使用本機PostgreSQL綁定的腳本語言中執行此操作。 – 2013-03-25 10:20:49

+0

哦,如果你堅持要用shell做所有事情,你可能遲早會需要協處理器。請參閱http://stackoverflow.com/q/7942632/398670 – 2013-03-25 10:23:29

+0

希望不是,我只需要將數據從基於文本文件的站點遷移到基於PGSQL的站點。 一切完成後,我只需備份數據庫。 :) 但謝謝你的鏈接。 – 2013-03-25 11:15:34

0

的最好的事情就是創建一個臨時表,COPY那些問題的文件,然後運行您的更新。

你的第二選擇是用pl/perlu這樣的語言創建一個函數,然後在存儲過程中這樣做,但是當你從臨時表中更新時,你將會失去很多性能優化。

2

psql無法直接讀取文件,除非您打算將其存儲爲大對象,在這種情況下您可以使用lo_import。請參閱psql命令\lo_import


更新:@AlexandreAlves指出,你可以實際上使用

\set myvar = `cat somefile` 

然後引用它作爲一個:'myvar'可變psql思樂普文件內容。便利。


雖然它可以讀取文件中使用shell和飼料它psql這將是笨拙充其量作爲外殼提供既不與參數化查詢的支持,也沒有逃避功能的任何文本的本地PostgreSQL數據庫驅動程序。你將不得不推出自己的字符串轉義。

即使如此,你需要知道輸入文件的文本編碼對你的client_encoding有效,否則你會插入垃圾和/或獲取錯誤。通過與Python,Perl,Ruby或Java等PostgreSQL的適當集成,它很快就可以輕鬆實現。

辦法做你想要在bash如果你真的必須,但:使用PG的delimited dollar quoting用隨機分隔符,以幫助防止SQL注入攻擊。這並不完美,但它非常貼心。我現在正在寫一個例子。


鑑於問題的文件:

$ cat > difficult.txt <__END__ 
Shell metacharacters like: $!(){}*?"' 
SQL-significant characters like "'() 
__END__ 

和樣表:

psql -c 'CREATE TABLE testfile(filecontent text not null);' 

您可以:

#!/bin/bash 
filetoread=$1 
sep=$(printf '%04x%04x\n' $RANDOM $RANDOM) 
psql <<__END__ 
INSERT INTO testfile(filecontent) VALUES (
\$x${sep}\$$(cat ${filetoread})\$x${sep}\$ 
); 
__END__ 

這可能是一個有點難以閱讀和隨機字符串生成是bash指定的c,儘管我確定可能有便攜式方法。

生成一個由字母數字字符組成的隨機標記字符串(爲方便起見,我使用了十六進制),並將其存儲在seq中。

psql然後用一個沒有引用的here-document標籤來調用。缺少引用是很重要的,因爲<<'__END__'會告知bash不要解釋字符串中的shell元字符,而只有簡單的<<__END__才允許shell解釋它們。我們需要shell來解釋元字符,因爲我們需要將sep替換爲here文檔,並且還需要使用$(...)(相當於反引號)來插入文件文本。在seq的每個替換之前的x是有的,因爲here-document標記必須是有效的PostgreSQL標識符,因此它們必須以字母而不是數字開頭。每個標籤的開頭和結尾處都有一個美元符號,因爲PostgreSQL美元報價格式爲$taghere$quoted text$taghere$

所以當腳本調用爲bash testscript.sh difficult.txt here文檔的土地高達擴大到類似:

INSERT INTO testfile(filecontent) VALUES (
$x0a305c82$Shell metacharacters like: $!(){}*?"' 
SQL-significant characters like "'()$x0a305c82$ 
); 

在標籤每一次變化,使得SQL注入的攻擊依賴於過早地結束報價困難。

我仍然建議你使用真正的腳本語言,但這表明它確實有可能。

+1

設置Postgres變量不需要等號(=),如上面更新中所示。簡單地使用:'\ set myvar \'cat somefile \'' – 2014-06-06 12:38:25