基于txt文件更新表行

时间:2013-03-25 03:08:41

标签: postgresql shell

我一直在搜索,但到目前为止我只发现了如何根据csv文件在表中插入日期。

我有以下情况:

目录名= 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创建一些东西并阅读和更新记录会更好,尽管我想避免这种方法。

由于 亚历

3 个答案:

答案 0 :(得分: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

缺点是它将始终创建一个新连接,稍后我将更改为创建单个文件

但它完全符合我的要求,将内容放在一个列中。

答案 1 :(得分:2)

psql无法直接读取该文件,除非您打算将其存储为大对象,在这种情况下您可以使用lo_import。请参阅psql命令\lo_import


更新:@AlexandreAlves指出您可以使用

实际上污染文件内容
  \set myvar = `cat somefile`

然后将其作为psql变量引用:'myvar'。方便。


虽然可以使用shell读取文件并将其提供给psql,但它最好是尴尬,因为shell既不提供具有参数化查询支持的本机PostgreSQL数据库驱动程序,也不提供任何文本转义函数。你必须滚动自己的字符串转义。

即便如此,您还需要知道输入文件的文本编码对您的client_encoding有效,否则您将插入垃圾和/或获取错误。通过与PostgreSQL(如Python,Perl,Ruby或Java)的适当集成,可以更快地实现这一目标。

是一种在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的,但我确信可能存在可移植的方法。

生成一个由字母数字字符组成的随机标记字符串(为方便起见,我使用了十六进制),并将其存储在seq中。

然后使用未引用的here-document标记调用

psql。缺少引用很重要,因为<<'__END__'会告诉bash不要解释字符串中的shell元字符,而普通<<__END__允许shell解释它们。我们需要shell来解释元字符,因为我们需要将sep替换为here文档,并且还需要使用$(...)(相当于反引号)来插入文件文本。每次替换x之前的seq都在那里,因为here-document标签必须是有效的PostgreSQL标识符,所以它们必须以字母而不是数字开头。每个标签的开头和结尾都有一个转义的美元符号,因为PostgreSQL美元报价的格式为$taghere$quoted text$taghere$

因此,当脚本被调用为bash testscript.sh difficult.txt时,此处的文档会扩展为:

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

每次标记都有所不同,使得SQL注入漏洞依赖于过早结束引用的难度。

我仍然建议您使用真正的脚本语言,但这表明它确实可行。

答案 2 :(得分:0)

最好的办法是创建一个临时表,从相关文件中复制那些表,然后运行更新。

你的第二个选择是用pl / perlu这样的语言创建一个函数,并在存储过程中执行此操作,但是当你从临时表更新时,你将失去很多性能优化。