Perl - не отправлять двойной запрос sql - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть Perl-скрипт, и я не хочу отправлять двойной запрос:

запрос «2018-03-15 12:30:00», «Метрика А», 62, и я хочу отправить только один раз и не более:

в моем mariadb bdd у меня есть двойная строка:

 SELECT time, measurement, valueOne FROM `metric_values`;

результаты:

+---------------------+-----------------+----------+ 
| time                | measurement     | valueOne |
+---------------------+-----------------+----------+ 
| 2018-03-15 12:30:00 | Metric A        |       62 | 
| 2018-03-15 12:30:00 | Metric A        |       62 |

Мой Perl Scipt:

use DBI;
open (FILE, 'logfile');
while (<FILE>) {

($word1, $word2, $word3, $word4, $word5, $word6, $word7, $word8, $word9, $word10, $word11, $word12, $word13, $word14) = split(" ");

$word13 =~ s/[^\d.]//g;


    if ($word13 > 5) {

        if ($word2 eq "Jan") {

        $word2 = "01"
        }

        if ($word2 eq "Feb") {

        $word2 = "02"
        }

        if ($word2 eq "Mar") {

        $word2 = "03"
        }

        if ($word2 eq "Apr") {

        $word2 = "04"
        }

        if ($word2 eq "May") {

        $word2 = "05"
        }

        if ($word2 eq "Jun") {

        $word2 = "06"
        }

        if ($word2 eq "Jul") {

        $word2 = "07"
        }

        if ($word2 eq "Aug") {

        $word2 = "08"
        }

        if ($word2 eq "Sep") {

        $word2 = "09"
        }

        if ($word2 eq "Oct") {

        $word2 = "10"
        }

        if ($word2 eq "Nov") {

        $word2 = "11"
        }

        if ($word2 eq "Dec") {

        $word2 = "12"
        }

        print "'$word5-$word2-$word3 $word4', $word11, $word13 \n";

              }
    # Connect to the database.
    my $dbh = DBI->connect("DBI:mysql:database=db;host=ip",
                           "titi", 'mp!',
                           {'RaiseError' => 1}) ;


    my $sth = $dbh->prepare(

        "INSERT `metric_values` (time, measurement, valueOne) VALUES('$word5-$word2-$word3 $word4', $word11, $word13);")#result is ('2018-03-15 12:30:00', 'Metric A', 62)

        or die "prepare statement failed: $dbh->errstr()";
    $sth->execute() or die "execution failed: $dbh->errstr()";
    print $sth->rows . " rows found.\n";

    $sth->finish;

мой файл журнала:

Wed Oct 17 04:57:08 2018 : Resource = 'toto' cstep= 'titi' time =23.634s 
Wed Oct 17 04:57:50 2018 : Resource = 'toto' cstep= 'titi' time =22.355s 

спасибо за ваш ответ

1 Ответ

0 голосов
/ 09 ноября 2018

В комментарии вы говорите так:

Я выполняю этот скрипт каждые 5 минут, и это создает много одинаковых строк в таблице, я не хочу, чтобы одна и та же строка в моей таблице

Я думаю, что это именно то, что происходит.

Каждые пять минут вы запускаете свою программу.Каждый раз, когда вы запускаете программу, вы используете один и тот же файл журнала для ввода.Таким образом, одни и те же записи обрабатываются каждый раз, и новые копии данных вставляются при каждом запуске.

Нет ничего плохого в существующем коде.Он делает именно то, что вы просили.Это просто не достаточно умно.Вы должны сделать это умнее.У вас есть несколько вариантов.

  1. Удалить из файла журнала записи, которые были обработаны.Таким образом, вы вставляете каждую запись только один раз.
  2. Добавьте флаг к каждой записи в вашем файле журнала, который указывает, что она была добавлена ​​в базу данных.Затем вы можете проверить этот флаг при обработке файла и вставлять только те записи, которые не имеют этого флага.
  3. Добавьте индекс в таблицу, чтобы убедиться, что он может содержать только одну копию каждой записи.Затем вам нужно будет изменить свой код, чтобы он игнорировал любые повторяющиеся ошибки данных, которые вы возвращаете из базы данных.
  4. Используйте REPLACE вместо INSERT и убедитесь, что у вас естьисправьте первичный ключ в своей таблице, чтобы гарантировать, что дубликаты записей не будут вставлены.

Не зная журнала больше о вашем конкретном приложении, трудно понять, какой из этих вариантов является лучшим для вас.Я подозреваю, что вам будет проще всего реализовать опцию REPLACE.

Обновление: Надеюсь, вы найдете некоторые общие комментарии к своему коду полезными.

Ваш код для открытия файла, конечно, работает, но он находится на некотором расстоянии от текущей лучшей практики.Я рекомендую а) использовать лексический дескриптор файла, б) использовать версию с тремя аргументами open() и в) проверить возвращаемое значение из вызова.

open my $fh, '<', 'logfile'
  or die "Could not open 'logfile': $!\n";

Используя переменные с именем $word1, $word2 и т. д. это ужасная идея.Лучше было бы использовать массив:

my @words = split ' ',

Если вы действительно хотите отдельные переменные, тогда, пожалуйста, дайте им лучшие имена:

my ($day, $mon, $date, $time, $year, ... ) = split(' ');

Лично я бы включил каждую записьв хеш.

my @cols = qw[day mon date time year ... ];

# and then, in your loop
my %record;
@record{@cols} = split ' ';

Преобразование месяца в число, как вы это делаете, неуклюже.Подумайте о настройке конверсионного хэша.

my %months = (
  Jan => 1,
  Feb => 2,
  ...
);

Тогда ваш код становится (предполагая $mon вместо $word2):

$mon = sprintf '%02d', $months{$mon}
  or die "$mon is not a valid month\n";

Но, на самом деле, вы должны использовать что-то вроде Время :: Штучка для работы с датами и временем.

my $timestamp = "$day $mon $date $time $year";
my $tp = Time::Piece->strptime($timestamp, '%a %b %d %H:%M:%S $Y');
say $tp->ymd, ' ', $tp->hms;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...