1

我一直在搜索,但到目前为止,我只找到了如何将日期插入基于 csv 文件的表中。

我有以下情况:

目录名称 = ticketID

在此目录中,我有几个文件,例如:

  • Description.txt
  • Summary.txt - 包含票头并已成功导入。
  • Progress_#.txt- 这是每次更新票证时。我得到一个新文件。
  • 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

3 回答 3

5

感谢您的回答,但我遇到了这个:

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

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

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

于 2013-03-25T07:40:53.183 回答
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 的分隔美元引号和随机分隔符来帮助防止 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.

psql然后使用未引用的 here-document 标记调用。缺少引号很重要,因为它<<'__END__'会告诉bash不要解释字符串中的 shell 元字符,而 plain<<__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 注入漏洞变得困难。

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

于 2013-03-25T04:31:58.543 回答
0

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

您的次要选择是使用 pl/perlu 之类的语言创建一个函数并在存储过程中执行此操作,但是您将失去很多从临时表更新时可以执行的性能优化。

于 2013-03-25T04:31:13.397 回答