我正在构建一个包含有关网络主机信息的数据库。我在PHPMaker生成的网站上提供这些数据。 (http://www.hkvstore.com/phpmaker/)
该项目的目的是建立一个IP地址管理系统。
重要的是我们保留数据库中任何记录的历史数据。如果我们手动更改PHPMaker构建站点上的记录,我们可以将旧记录数据写入另一个表。用于实现此目的的代码如下所示。 (可能不完全相关,但我把它放在这里,这样你就可以了解数据的样子)
$sInsertSql = "INSERT INTO IPHistoric (ip, status, hostname, last_scanned, mac, ManualHost, Reservation)
VALUES ('" . $rsold['ip'] . "', '" . $rsold['status'] . "', '" . $rsold['hostname'] . "', '" . $rsold['last_scanned'] . "', '" . $rsold['mac'] . "', '" . $rsold['ManualHost'] . "', '". $rsold['Reservation'] . "')";
现在,我还使用名为nmap2db.pl(http://search.cpan.org/~apersaud/Nmap-Parser-1.2/tools/nmap2db.pl)的perl脚本填充数据,这使得对子网进行nmap扫描并将该数据填充到表中非常容易。
我需要什么:
我需要perl脚本将任何旧数据保存到IPHistoric表而不是每次都覆盖。 我对脚本做了一些细微的修改(从数据库模式中删除了一些字段)
完整脚本的Pastebin: http://pastebin.com/V3AwcBVR
看起来第92到第95行是神奇发生的地方。
$S{INSERT_HOST}
= qq{REPLACE INTO }
. $G{TABLE}
. qq{ (ip, mac, status, hostname) VALUES (?,?,?,?)};
所以无论如何......我不知道Perl,我不擅长SQL。是否清楚我想要实现什么?是否可以编辑此脚本来执行我想要的操作?
答案 0 :(得分:1)
这看起来非常简单。
但是,现在数据库的结构方式,主键是IP地址。
#Schema for table, simple for now
$S{CREATE_TABLE} = qq{ CREATE TABLE } . $G{TABLE} . qq{ (
ip VARCHAR(15) PRIMARY KEY NOT NULL,
mac VARCHAR(17) ,
status VARCHAR(7) DEFAULT 'Down',
hostname VARCHAR(50),
last_scanned TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
};
此架构仅允许每个IP地址使用一条记录,这意味着如果使用新数据更新现有记录,旧数据将被丢弃。
您可以通过从IP地址的表架构中删除主键约束来防止这种情况,而是将其放在例如mac地址上。由于mac地址在统计上是唯一的,所以你不应该得到重复。如果你有一个声称拥有多个IP地址的mac地址,你可能还是想了解这一点。
从ip列中删除主键约束后,您现在可以拥有相同IP地址的多条记录。诀窍是找出哪一个是最新的。你可以用时间戳来做到这一点。在数据库中创建两个额外的列,并将其称为CREATE_TIME和END_TIME。
每次在数据库中插入记录时,都会将当前时间戳插入CREATE_TIME。如果该ip的记录已存在,请将当前时间戳插入END_TIME,然后创建新记录。这样,您就可以根据CREATE_TIME和END_TIME时间戳知道每条IP记录的分配时间。
由于END_TIME仅在更改记录时写入,因此您可以通过执行以下操作来获取当前的IP记录集:
select * from TABLE where END_TIME is NULL;
希望有道理。
答案 1 :(得分:0)
或者,使用“历史表”主题:
use vars qw(%S %G %H);
$H{TABLE} ||='IPHistoric';
$S{INSERT_HISTORIC}
= qq{INSERT INTO }
. $H{TABLE}
. qq{ (ip, status, hostname, last_scanned, mac, ManualHost, Reservation) VALUES (?,?,?,?,?,?,?)};
my $hist_ins = eval { $dbh->prepare_cached( $S{INSERT_HISTORIC} ) };
my $np = new Nmap::Parser;
$np->callback( \&insert_historic );
sub insert_historic {
my $host = shift;
my $os = $host->os_sig();
#ip, mac, status, hostname
my @input_values = (
$host->rsold['ip'],
$host->rsold['status'],
$host->rsold['hostname'],
$host->rsold['last_scanned'],
$host->rsold['mac'],
$host->rsold['ManualHost'],
$host->rsold['Reservation']
);
my $rv
= $hist_ins->execute(@input_values) ? "ok" : "OOPS! - " . DBI->errstr;
printf( "\t..> %-15s : (%4s) : %-s\n", $host->addr, $host->status, $rv );
}
这可能有一些错字,但你明白了。基本上,一旦设置了$ rsold变量,就可以调用insert_historic sub并将所有这些值保存到IPHistoric表中。
下面的代码不会独立运行,因为它依赖于您链接的代码中设置的许多其他内容。但是您应该能够复制/设置$ {INSERT_HOST}部分正下方的$ S {INSERT_HISTORIC}部分,而insert_historic子部分将位于insert_host子部分的正下方。
祝你好运!答案 2 :(得分:0)
我们添加了INSERT_HISTORY部分。
$S{INSERT_HISTORY}
= qq{ INSERT_INTO IPHistoric }
. qq{ ip, status, hostname, last_scanned, mac, ManualHost, Reservation }
. qq { SELECT ip, status, hostname, last_scanned, mac, ManualHost, Reservation FROM }
. $G{TABLE}
. qq { WHERE ip = ? AND ( mac <> ? OR hostname <> ? ) };
$S{UPDATE_HOST}
= qq{UPDATE }
. $G{TABLE}
. qq { SET mac = ? , status = ?, hostname = ?, last_scanned = CURRENT_TIMESTAMP }