需要将AoH中的一个值与第二个AoH中的另一个值进行比较

时间:2018-02-27 22:02:15

标签: arrays perl nested-loops

编辑更清晰:

我将从数据库中获取2个查询并将它们存储为AoH。这两个查询是:

select
    ip_address, 
    testnet,
    t.email as email, 
    owner, 
    hr_manager_login as manager
from 
    lab_view 
    JOIN CMN_INT.AK_EMPLOYEE on owner = login 
    JOIN testnets t on t.name = testnet
where 
    DIVISION like 'TERM%' and TERM_DATE is not null
order by owner

select login from CMN_INT.AK_EMPLOYEE where DIVISION = q[Terminated Employees]

对于我原来的测试,我不会潜入开放/使用DBI,所以我使用虚拟数据。我的$ qr是我从第一个查询得到的一个例子,我的$ qr2是我从第二个查询得到的一个例子。我想查看第一个AoH中的Manager值是否在第二个(终止员工)AoH中找到。如果找到,则经理是已终止的员工,其名称不应推送到%经理。我尝试通过将下面的foreach代码插入到我的第一个foreach代码中来测试它,但它不起作用,因为Harry仍然被推送和打印。

foreach my $emp2 (@$qr2){
    if ($emp->{Manager} ne $emp2->{Login}){
        $manager{$emp->{Manager}} = 1; #capture all managers not also terminated related to $name. Done this way for when $name is undef
    }
}

我还尝试将$ emp-> {Manager}分配给第二个foreach之前的变量,然后使用if($ M ne $ emp2-> {Login}),但这也无效。

下面是我的测试代码的第一部分,其中包含我将运行的查询的虚拟数据,减去所有的elsifs :)

my $qr = [
    {IP=>'X.Y.Z.51',Testnet=>'bos-por-leg',Owner=>'Edmund', Email => 'bosemail', Manager => 'Tod'},
    {IP=>'X.Y.Z.52',Testnet=>'bos-por-2',Owner=>'Edmund', Email => 'boemail2',Manager => 'Tod'},
    {IP=>'X.Y.Z.53',Testnet=>'bos-por-leg',Owner=>'Edmund', Email => 'bosemail',Manager => 'Tod'},
    {IP=>'X.Y.Z.54',Testnet=>'sqa',Owner=>'Richard', Email => 'sqaemail',Manager => 'Harry'},
    {IP=>'X.Y.Z.55',Testnet=>'sqa',Owner=>'Richard', Email => 'sqaemail',Manager => 'Harry'},
    {IP=>'X.Y.Z.56',Testnet=>'fll-pro',Owner=>'Larry', Email => 'fllemail',Manager => 'Moe'},
    {IP=>'X.Y.Z.57',Testnet=>'fll-pro', Owner=>'', Email => 'fllemail',Manager => 'Tod'},
    {IP=>'X.Y.Z.58',Testnet=>'fll-pro2', Owner=>'', Email => 'flemail2', Manager => 'Curly'},
];
my $qr2 = [{Login => 'Tom'},
           {Login => 'Dick'},
           {Login => 'Harry'},
           ];
my $len = scalar @$qr;
my $l = $len;
my $a = @$qr[0]->{Owner};
func ($a);
my %ip;
my %test;
my $name;
my %manager;
my $ip_ref;
my $test_ref;
my $man_ref;
sub func{
    foreach my $emp (@$qr) {
        if ($l > 1 && $emp->{Owner} eq $a) {
            $name = $emp->{Owner} || 'Undefined'; #to use with email as $a will change as cycle thru
            $ip{$emp->{IP}} = $emp->{Testnet}; #capture all IPs related to owner $name
            $test{$emp->{Testnet}} = $emp->{Email}; #capture unique testnets only related to owner $name
            foreach my $emp2 (@$qr2){
                if ($emp->{Manager} ne $emp2->{Login}){
                $manager{$emp->{Manager}} = 1; #capture all managers not also term related to $name. Done this way for when $name is undef
                }
            }
            $l--; #to cycle thru array until reach last row
        }
    }
}
sub mail_func{
    my $n = shift;   #user 
    my $i = shift;   #ips
    my $t = shift;   #testnets
    my $m = shift;   #managers (multiple if owner is undef) --> to field
    print "User name is: $n\n";
    my @to_list;
        foreach my $value (values %{$t}){
            if ($value ne 'bosemail'){
                if (grep {$value} @to_list){next;}
                else {push(@to_list,$value . '@email.com');}
            }
        }
    foreach my $key (keys %{$m}){push(@to_list,$key . '@email.com');}
    print "@to_list\n";
    my @body;
    while ( my ( $key, $value ) = each %{$i} ) {
        my $b = "IP " . $key . " : Testnet " . $value . "\n";
        push (@body, $b);
    }
    print "@body\n";
}

在测试中,我得到:

User name is: Richard
sqaemail@email.com Harry@email.com   ##Harry shouldn't be added
IP X.Y.Z.54 : Testnet sqa
 IP X.Y.Z.55 : Testnet sqa

我很欣赏有关如何纠正的所有意见。如果您需要更多代码,请告诉我们。另外需要注意的是,终止的员工名单很长,所以我猜我甚至不应该通过循环方法将一个AoH中的每个值与另一个AoH中的每个值进行比较,但这就是我所知道的全部:)我我试图看看是否有办法做我想要的只使用1个查询。谢谢。

1 个答案:

答案 0 :(得分:1)

除非我错过了一些明显的东西,否则我认为你的事情太复杂了。

以下适用于我。

警告:它使用'smartmatch operator'搜索数组中的元素。 AFAIK此功能仍被视为“实验性”。其他人也许可以评论该功能的状态 - 或建议更合适的选择。

use strict;
use warnings;
use feature 'say';

my $qr = [
    {IP=>'X.Y.Z.51',Testnet=>'bos-por-leg',Owner=>'Edmund', Email => 'bosemail', Manager => 'Tod'},
    {IP=>'X.Y.Z.52',Testnet=>'bos-por-2',Owner=>'Edmund', Email => 'boemail2',Manager => 'Tod'},
    {IP=>'X.Y.Z.53',Testnet=>'bos-por-leg',Owner=>'Edmund', Email => 'bosemail',Manager => 'Tod'},
    {IP=>'X.Y.Z.54',Testnet=>'sqa',Owner=>'Richard', Email => 'sqaemail',Manager => 'Harry'},
    {IP=>'X.Y.Z.55',Testnet=>'sqa',Owner=>'Richard', Email => 'sqaemail',Manager => 'Harry'},
    {IP=>'X.Y.Z.56',Testnet=>'fll-pro',Owner=>'Larry', Email => 'fllemail',Manager => 'Moe'},
    {IP=>'X.Y.Z.57',Testnet=>'fll-pro', Owner=>'', Email => 'fllemail',Manager => 'Tod'},
    {IP=>'X.Y.Z.58',Testnet=>'fll-pro2', Owner=>'', Email => 'flemail2', Manager => 'Curly'},
];

my $qr2 = [{Login => 'Tom'},
           {Login => 'Dick'},
           {Login => 'Harry'},
           ];

my @dismissed = map { $_->{Login} } @$qr2;

my @eligible = grep { !($_->{Manager} ~~ @dismissed) } @$qr;

say $_->{Testnet}, ', ', $_->{Email} foreach @eligible;

其他数据库查询

由于您使用Perl而不是DBI标记了问题,因此这是括号 - 但我认为值得注意。

你问:

  

我也试图看看是否有办法只使用我想要的东西   1个查询

我认为有 - 使用NOT IN运算符。类似于以下内容可能会起作用 - 尽管您可能需要稍微改变语法,具体取决于您使用的数据库服务器。

简单地为WHERE子句添加另一个条件,所以

where 
    DIVISION like 'TERM%' and TERM_DATE is not null

会变成

where 
    DIVISION like 'TERM%' and TERM_DATE is not null
AND
    hr_manager_login NOT IN (select login from CMN_INT.AK_EMPLOYEE where DIVISION = q[Terminated Employees])

如果已终止员工的数量非常长(您的关注时间很长' - 但未指定确切的长度),使用NOT IN可能会对性能产生影响,但我认为这可能不是这种情况。