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

Need to compare one value in AoH to another value in a second AoH

编辑更清楚:

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

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]

对于我最初的测试,我不打算深入研究 opening/using DBI,所以我使用了虚拟数据。我的 $qr 是我从第一个查询中得到的一个例子,我的 $qr2 是我从第二个查询中得到的一个例子。我想查看第一个 AoH 中的 Manager 值是否在第二个(已离职员工)AoH 中找到。如果找到,则该经理是已离职的员工,不应将其姓名推送给 %manager。我尝试通过将下面的 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
    }
}

我还尝试在第二个 foreach 之前将 $emp->{Manager} 分配给一个变量,然后使用 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 个查询来做我想做的事情。谢谢。

除非我遗漏了一些明显的东西,否则我认为你把事情搞得太复杂了。

以下适合我。

警告: 它使用 'smartmatch operator' 来搜索数组中的元素。据我所知,此功能仍被视为 'experimental'。其他人可能能够评论该功能的状态 - 或者建议更合适的替代方案。

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 标记了问题,所以这是附加的 - 但我认为仍然值得注意。

您问的是:

I am trying to also see if there is a way to do what I want using only 1 query

我认为有 - 使用 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])

如果被解雇的员工人数 非常长(您暗示它是 'quite long' - 但没有具体说明多长时间)可能会对性能产生影响使用 NOT IN,但我认为这里可能不是这种情况。