如何使用Perl解析sqlplus命令的输出?

时间:2010-05-01 08:03:59

标签: sql perl unix

我有一个SQL文件,它会给我一个如下输出:

10|1
10|2
10|3
11|2
11|4
.
.
.

我在下面的Perl脚本中使用它:

my @tmp_cycledef = `sqlplus -s $connstr \@DLCycleState.sql`;

在上面的语句之后,因为@tmp_cycledef具有SQL查询的所有输出, 我想将输出显示为:

10 1,2,3
11 2,4

我怎么能用Perl做到这一点?

编辑:

我使用以下代码:

foreach  my $row (@tmp_cycledef)
{
        chomp $row;
        my ($cycle_code,$cycle_month)= split /\s*\|\s*/, $row;
        print "$cycle_code, $cycle_month\n";
        $hash{$cycle_code}{$cycle_month}=1
}

foreach my $num ( sort keys %hash )
{
        my $h = $hash{$num};
        print join(',',sort keys %$h),"\n";
}

第一个print语句打印出来:

     2, 1
     2, 10
     2, 11
     2, 12
     3, 1
     3, 10
     3, 11

但外出总是

1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12
1,10,11,12

3 个答案:

答案 0 :(得分:1)

使用hash of arrays收集单个密钥的所有值,然后将其打印出来:

init hash
for each line:
  parse into key|value
  append value to hash[key]

for each key in hash:  # you can sort it, if needed 
  print out key, list of values

答案 1 :(得分:1)

嗯,这个实际上是你在 perl 中的方式:

# two must-have pragmas for perl development
use strict;    
use warnings;

Perl允许在使用变量时创建变量,$feldman = some_function()表示您现在在本地名称空间中拥有变量$feldman。但关于这一点的不好的部分是你可以输入$fldman并花很长时间找出你认为$feldman没有价值的原因。启用strictures意味着如果遇到未声明的变量,您的代码将无法编译。您使用myour语句声明变量(或使用旧的Perl代码声明use vars语句。

当您没有获得预期的价值时,启用warnings会警告您。通常警告往往过于敏感,但它们通常 开发代码是一件好事。

my %hash; # the base object for the data

在这里,我已经声明了一个我创造性地称为%hash的哈希变量。 sigil(发音为“sijil”)“%”表示它是名称 - 值对的映射。这个my语句声明了变量并使其对编译器合法。编译器会警告我使用%hsh

下一个项目是foreach循环(可以缩写为“for”)。循环将处理@tmp_cycledef中的行列表,依次将每个行分配给$row。 (我的 $row)。

  1. 我们先chomp行,删除该平台的行尾字符。
  2. 我们split“|”上的一行字符,创建已由管道分隔的字符串列表。
  3. 然后我们将它存储在一个双层哈希中。因为我们想要将它们分组至少第一个数字。我们可以通过数组执行此操作,并在哈希中的位置创建一个数组,如:push @{$hash{$key}}, $val,但我通常想要折叠重复项(而不是样本中有任何重复项。)
  4. 下面:

    foreach my $row ( @tmp_cycledef ) { 
        chomp $row; # removes the end-of-line character when present. 
        my ( $key, $val ) = split /\|/, $row; 
        # One of the best ways to merge lists is a presence-of idea
        # with the hash holding whether the value is present
        $hash{$key}{$val} = 1; 
    }
    

    一旦我们在结构中有数据,我们就需要迭代两个哈希值keys。您希望按行分隔“顶级”数字,但您希望第二个数字在同一行上连接。因此,我们为每个第一个数字打印一行,并join为同一行上的每个数字存储的字符串列表,用逗号分隔。我们还排序列表:{ $a <=> $b }只需要键,以数字方式比较它们。所以你得到一个数字订单。

    # If they were alpha keys our sort routine, we would just likely say sort keys %hash
    foreach my $num ( sort { $a <=> $b } keys %hash ) { 
        my $h = $hash{$num};
        print "$num ", join( ',', sort { $a <=> $b } keys %$h ), "\n";
    }
    

    正如我在评论中所说,默认情况下,sort按字符顺序排序,因此您只需说sort keys %hash即可。

    为了帮助你,你真的需要阅读其中一些:

答案 2 :(得分:0)

如果您的输入已排序(就像在提供的示例中那样),您实际上不需要打扰数组/哈希的哈希值。代码有点长,但不要求您理解引用,并且应该对大型数据集运行得更快:

#!/usr/bin/perl

use strict;
use warnings;

my @tmp_cycledef = <DATA>;

my $last_key;
my @values;
for (@tmp_cycledef) {
  chomp;
  my ($key, $val) = split '\|';

  # Seed $last_key with the first key value on the first pass
  $last_key = $key unless defined $last_key;

  # The key has changed, so it's time to print out the values associated
  # with the previous key, then reset everything for the new one
  if ($key != $last_key) { 
    print "$last_key " . join(',', @values) . "\n";
    $last_key = $key;
    @values = ();
  }

  # Add the current value to the list of values for this key
  push @values, $val;
}

# Don't forget to print out the final key when you're done!
print "$last_key " . join(',', @values) . "\n";

__DATA__
10|1
10|2
10|3
11|2
11|4