【问题标题】:updating table rows based on txt file基于txt文件更新表行
【发布时间】:2013-03-25 03:08:40
【问题描述】:

我一直在搜索,但到目前为止,我只找到了如何根据 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 做一些东西并读取和更新记录会更好,尽管我想避免这种方法。

谢谢 亚历克斯

【问题讨论】:

    标签: postgresql shell


    【解决方案1】:

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

    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
    

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

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

    【讨论】:

    • 太好了,谢谢;我不知道psql 支持\set 中的反引号命令调用。这很方便,尽管我重申了我的建议,即停止尝试在 shell 和具有本机 PostgreSQL 绑定的脚本语言中执行此操作。
    • 哦,如果你坚持用 shell 做所有事情,你可能迟早会需要协同处理。见stackoverflow.com/q/7942632/398670
    • 希望不是,我只需要将数据从基于文本文件的站点迁移到基于 PGSQL 的站点。一切完成后,我将备份数据库。 :) 但是谢谢你的链接。
    • 请注意\set content = `cat PATH/Description.txt` 将在:'content' 的值前面放置一个前导= - 仅推荐\set content `cat PATH/Description.txt`
    • @nezda 是对的。我也刚遇到这个问题。我已要求对答案进行编辑,以免其他人落入这个陷阱
    【解决方案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中。

    psql 然后使用未引用的 here-document 标记调用。没有引用很重要,因为&lt;&lt;'__END__' 会告诉bash 不要解释字符串中的shell 元字符,而普通的&lt;&lt;__END__ 允许shell 解释它们。我们需要 shell 来解释元字符,因为我们需要将 sep 替换到此处的文档中,并且还需要使用 $(...)(相当于反引号)来插入文件文本。每次替换 seq 之前的 x 都存在,因为 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 注入攻击变得困难。

    我还是建议你使用真正的脚本语言,但这说明确实是可以的。

    【讨论】:

    • 设置 Postgres 变量不需要等号 (=),如上面的更新所示。只需使用:\set myvar `cat somefile`
    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-23
      • 1970-01-01
      • 2015-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-14
      相关资源
      最近更新 更多