1 package C4::SearchBiblio;
3 # Copyright 2000-2002 Katipo Communications
5 # This file is part of Koha.
7 # Koha is free software; you can redistribute it and/or modify it under the
8 # terms of the GNU General Public License as published by the Free Software
9 # Foundation; either version 2 of the License, or (at your option) any later
12 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License along with
17 # Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
18 # Suite 330, Boston, MA 02111-1307 USA
28 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
30 # set the version for version checking
35 C4::Search - Functions for searching the Koha MARC catalog
39 This module provides the searching facilities for the Koha MARC catalog
44 @EXPORT = qw(&catalogsearch1 &catalogsearch &findseealso &findsuggestion &getMARCnotes &getMARCsubjects);
46 =head1 findsuggestion($dbh,$values);
48 =head2 $dbh is a link to the DB handler.
51 my $dbh =C4::Context->dbh;
53 =head2 $values is a word
55 Searches words with the same soundex, ordered by frequency of use.
56 Useful to suggest other searches to the users.
61 my ($dbh,$values) = @_;
62 my $sth = $dbh->prepare("SELECT count( * ) AS total, word FROM marc_word WHERE sndx_word = soundex( ? ) AND word <> ? GROUP BY word ORDER BY total DESC");
64 for(my $i = 0 ; $i <= $#{$values} ; $i++) {
65 if (length(@$values[$i]) >=5) {
66 $sth->execute(@$values[$i],@$values[$i]);
69 while ((my ($count,$word) = $sth->fetchrow) and $resfound <=10) {
70 push @results, "@$values[$i]|$word|$count";
71 # $results{@$values[$i]} = \@resline;
79 =head1 findseealso($dbh,$fields);
81 =head2 $dbh is a link to the DB handler.
84 my $dbh =C4::Context->dbh;
86 =head2 $fields is a reference to the fields array
88 This function modify the @$fields array and add related fields to search on.
93 my ($dbh, $fields) = @_;
94 my $tagslib = MARCgettagslib ($dbh,1);
95 for (my $i=0;$i<=$#{$fields};$i++) {
96 my ($tag) =substr(@$fields[$i],1,3);
97 my ($subfield) =substr(@$fields[$i],4,1);
98 @$fields[$i].=','.$tagslib->{$tag}->{$subfield}->{seealso} if ($tagslib->{$tag}->{$subfield}->{seealso});
102 =head1 my ($count, @results) = catalogsearch($dbh, $tags, $and_or, $excluding, $operator, $value, $offset,$length,$orderby,$sqlstring);
104 =head2 $dbh is a link to the DB handler.
107 my $dbh =C4::Context->dbh;
109 $tags,$and_or, $excluding, $operator, $value are references to array
113 contains the list of tags+subfields (for example : $@tags[0] = '200a')
114 A field can be a list of fields : '200f','700a','700b','701a','701b'
120 contains a list of strings containing and or or. The 1st value is useless.
124 contains 0 or 1. If 1, then the request is negated.
128 contains contains,=,start,>,>=,<,<= the = and start work on the complete subfield. The contains operator works on every word in the subfield.
131 contains home, search home anywhere.
132 = home, search a string being home.
136 contains the value to search
137 If it contains a * or a %, then the search is partial.
139 =head2 $offset and $length
141 returns $length results, beginning at $offset
145 define the field used to order the request. Any field in the biblio/biblioitem tables can be used. DESC is possible too
147 (for example title, title DESC,...)
151 optional argument containing an sql string to be used in the 'where' statement. see usage in opac-search.pl.
155 returns an array containing hashes. The hash contains all biblio & biblioitems fields and a reference to an item hash. The "item hash contains one line for each callnumber & the number of items related to the callnumber.
159 =head2 my $marcnotesarray = &getMARCnotes($dbh,$bibid,$marcflavour);
161 Returns a reference to an array containing all the notes stored in the MARC database for the given bibid.
162 $marcflavour ("MARC21" or "UNIMARC") determines which tags are used for retrieving subjects.
164 =head2 my $marcsubjctsarray = &getMARCsubjects($dbh,$bibid,$marcflavour);
166 Returns a reference to an array containing all the subjects stored in the MARC database for the given bibid.
167 $marcflavour ("MARC21" or "UNIMARC") determines which tags are used for retrieving subjects.
172 my ($dbh, $tags, $and_or, $excluding, $operator, $value, $offset,$length,$orderby,$desc_or_asc,$sqlstring) = @_;
173 # warn "==================";
176 # tags_array: @$tags,
177 # andor_array: @$and_or,
178 # excludes_array: @$excluding,
179 # operator_array: @$operator,
180 # value_array: @$value,
182 # resultsperpage: $length,
184 # order: $desc_or_asc,
185 # sqlstring: $sqlstring)\n";
186 # warn "==================\n";
188 my @cols = ('biblionumber','author','title','unititle','notes','serial','seriestitle',
189 'copyrightdate','timestamp','abstract','illus','biblioitemnumber','marc',
190 'url','isbn','volumeddesc','classification','publicationyear','pages','number',
191 'itemtype','place','issn','size','dewey','publishercode','lccn','volume',
192 'subclass', 'volumedate','subtitle','bibid','notforloan',);
193 # missing 'CN', 'description', 'odd', 'bn', 'norequests', 'totitem',
194 my @valarray = @$value;
196 # warn "$valarray[0]\n";
198 SELECT biblio.biblionumber, biblio.author, biblio.title, biblio.unititle,
199 biblio.notes, biblio.serial, biblio.seriestitle, biblio.copyrightdate,
200 biblio.timestamp, biblio.abstract,
201 biblioitems.illus, biblioitems.biblioitemnumber, biblioitems.marc,
202 biblioitems.url, biblioitems.isbn, biblioitems.volumeddesc,
203 biblioitems.classification, biblioitems.publicationyear,
204 biblioitems.pages, biblioitems.number, biblioitems.itemtype,
205 biblioitems.place, biblioitems.issn, biblioitems.size,
206 biblioitems.dewey, biblioitems.publishercode, biblioitems.lccn,
207 biblioitems.volume, biblioitems.subclass, biblioitems.volumedate,
208 bibliosubtitle.subtitle,
211 MATCH(biblio.title,biblio.author,biblio.unititle,biblio.seriestitle)
212 AGAINST ('$$value[0]' IN BOOLEAN MODE) as Relevance
214 LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
215 LEFT JOIN bibliosubtitle ON bibliosubtitle.biblionumber=biblio.biblionumber
216 LEFT JOIN marc_biblio ON marc_biblio.biblionumber=biblio.biblionumber
217 LEFT JOIN items ON items.biblionumber=biblio.biblionumber
218 WHERE MATCH(biblio.title,biblio.author,biblio.unititle,biblio.seriestitle)
219 AGAINST ('$$value[0]' IN BOOLEAN MODE)
220 ORDER BY Relevance DESC;";
222 my $sth = $dbh->prepare($sql);
226 while (my @vals = $sth->fetchrow) {
227 my $numcols = $#vals;
228 my %biblioEntryHash=();
229 for(my $i=0; $i<$numcols; $i++) {
230 $biblioEntryHash{$cols[$i]} = $vals[$i];
232 $biblioEntryHash{odd} = ((($numBooks+1) % 2) > 0) ? 1 : "";
234 $biblioEntryHash{notforloan} = "";
235 #warn "\$biblioEntryHash{odd} = .$biblioEntryHash{odd}.\n";
236 push(@biblioArray,\%biblioEntryHash);
241 # CN: ARRAY(0x89d1540)? branch + location + callnumber + status
242 # CDI SL (N8KIM) (2) (if several, group them)
245 # bn: 501? biblionumber?
249 # my ($res,$numres) = catalogsearch(@_);
250 # my @results = @$res;
251 # warn "==================\n";
252 # warn "\n\tres: @$res:,\n\tnumres: $numres\n";
253 # while ( (my ($key, $value) = each(%{$results[0]})) && (my ($key1, $value1) = each(%{$biblioArray[0]})) ) {
254 # warn "\t$key => $value\t$key1 => $value1\n";
256 # warn "a. " . $results[0]->{odd} . "\t" . $biblioArray[0]->{odd}. "\n";
257 # warn "b. " . $results[1]->{odd} . "\t" . $biblioArray[1]->{odd}. "\n";
258 # warn "==================\n";
259 #return ($res,$numres);
260 return (\@biblioArray,$numBooks);
264 my ($dbh, $tags, $and_or, $excluding, $operator, $value, $offset,$length,$orderby,$desc_or_asc,$sqlstring) = @_;
265 # build the sql request. She will look like :
267 # from marc_subfield_table as m1, marc_subfield_table as m2
268 # where m1.bibid=m2.bibid and
269 # (m1.subfieldvalue like "Des%" and m2.subfieldvalue like "27%")
271 # last minute stripping out of stuff
272 # doesn't work @$value =~ s/\'/ /;
273 # @$value = map { $_ =~ s/\'/ /g } @$value;
275 # "Normal" statements
276 my @normal_tags = ();
277 my @normal_and_or = ();
278 my @normal_operator = ();
279 my @normal_value = ();
280 # Extracts the NOT statements from the list of statements
283 my @not_operator = ();
286 $orderby = "biblio.title" unless $orderby;
287 $desc_or_asc = "ASC" unless $desc_or_asc;
288 #last minute stripping out of ' and ,
289 # paul : quoting, it's done a few lines lated.
290 # foreach $_ (@$value) {
295 # the item.notforloan contains an integer. Every value <>0 means "book unavailable for loan".
296 # but each library can have it's own table of meaning for each value. Get them
297 # 1st search if there is a list of authorised values connected to items.notforloan
298 my $sth = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield="items.notforloan"');
300 my %notforloanstatus;
301 my ($authorised_valuecode) = $sth->fetchrow;
302 if ($authorised_valuecode) {
303 $sth = $dbh->prepare("select authorised_value,lib from authorised_values where category=?");
304 $sth->execute($authorised_valuecode);
305 while (my ($authorised_value,$lib) = $sth->fetchrow) {
306 $notforloanstatus{$authorised_value} = $lib?$lib:$authorised_value;
309 for(my $i = 0 ; $i <= $#{$value} ; $i++)
312 @$value[$i] =~ s/\*/%/g;
313 # remove % at the beginning
314 @$value[$i] =~ s/^%//g;
315 @$value[$i] =~ s/(\.|\?|\:|\!|\'|,|\-|\"|\(|\)|\[|\]|\{|\}|\/)/ /g if @$operator[$i] eq "contains";
316 if(@$excluding[$i]) # NOT statements
319 if(@$operator[$i] eq "contains")
321 foreach my $word (split(/ /, @$value[$i])) # if operator is contains, splits the words in separate requests
323 # remove the "%" for small word (3 letters. (note : the >4 is due to the % at the end)
324 # warn "word : $word";
325 $word =~ s/%//g unless length($word)>4;
326 unless (C4::Context->stopwords->{uc($word)} or length($word)==1) { #it's NOT a stopword => use it. Otherwise, ignore
327 push @not_tags, @$tags[$i];
328 push @not_and_or, "or"; # as request is negated, finds "foo" or "bar" if final request is NOT "foo" and "bar"
329 push @not_operator, @$operator[$i];
330 push @not_value, $word;
336 push @not_tags, @$tags[$i];
337 push @not_and_or, "or"; # as request is negated, finds "foo" or "bar" if final request is NOT "foo" and "bar"
338 push @not_operator, @$operator[$i];
339 push @not_value, @$value[$i];
342 else # NORMAL statements
344 if(@$operator[$i] eq "contains") # if operator is contains, splits the words in separate requests
346 foreach my $word (split(/ /, @$value[$i]))
348 # remove the "%" for small word (3 letters. (note : the >4 is due to the % at the end)
349 # warn "word : $word";
350 $word =~ s/%//g unless length($word)>4;
351 unless (C4::Context->stopwords->{uc($word)} or length($word)==1) { #it's NOT a stopword => use it. Otherwise, ignore
352 push @normal_tags, @$tags[$i];
353 push @normal_and_or, "and"; # assumes "foo" and "bar" if "foo bar" is entered
354 push @normal_operator, @$operator[$i];
355 push @normal_value, $word;
361 push @normal_tags, @$tags[$i];
362 push @normal_and_or, @$and_or[$i];
363 push @normal_operator, @$operator[$i];
364 push @normal_value, @$value[$i];
369 # Finds the basic results without the NOT requests
370 my ($sql_tables, $sql_where1, $sql_where2) = create_request($dbh,\@normal_tags, \@normal_and_or, \@normal_operator, \@normal_value);
371 $sql_where1 .=" ". $sqlstring;
372 $sql_where1 .= "and TO_DAYS( NOW( ) ) - TO_DAYS( biblio.timestamp ) <30" if $orderby =~ "biblio.timestamp";
375 $sth = $dbh->prepare("select distinct m1.bibid from biblio,biblioitems,items,marc_biblio,$sql_tables where biblio.biblionumber=marc_biblio.biblionumber and biblio.biblionumber=biblioitems.biblionumber and m1.bibid=marc_biblio.bibid and $sql_where2 and ($sql_where1) order by $orderby $desc_or_asc");
376 warn "Q2 : select distinct m1.bibid from biblio,biblioitems,items,marc_biblio,$sql_tables where biblio.biblionumber=marc_biblio.biblionumber and biblio.biblionumber=biblioitems.biblionumber and m1.bibid=marc_biblio.bibid and $sql_where2 and ($sql_where1) order by $orderby $desc_or_asc term is @$value";
378 $sth = $dbh->prepare("select distinct m1.bibid from biblio,biblioitems,items,marc_biblio,$sql_tables where biblio.biblionumber=marc_biblio.biblionumber and biblio.biblionumber=biblioitems.biblionumber and m1.bibid=marc_biblio.bibid and $sql_where1 order by $orderby $desc_or_asc");
379 warn "Q : select distinct m1.bibid from biblio,biblioitems,items,marc_biblio,$sql_tables where biblio.biblionumber=marc_biblio.biblionumber and biblio.biblionumber=biblioitems.biblionumber and m1.bibid=marc_biblio.bibid and $sql_where1 order by $orderby $desc_or_asc";
383 my $subtitle; # Added by JF for Subtitles
385 # Processes the NOT if any and there are results
386 my ($not_sql_tables, $not_sql_where1, $not_sql_where2);
388 if( ($sth->rows) && $any_not ) # some results to tune up and some NOT statements
390 ($not_sql_tables, $not_sql_where1, $not_sql_where2) = create_request($dbh,\@not_tags, \@not_and_or, \@not_operator, \@not_value);
394 while (my ($bibid) = $sth->fetchrow) {
395 push @tmpresult,$bibid;
398 warn "NOT : select distinct m1.bibid from $not_sql_tables where $not_sql_where2 and ($not_sql_where1)";
399 if ($not_sql_where2) {
400 $sth_not = $dbh->prepare("select distinct m1.bibid from $not_sql_tables where $not_sql_where2 and ($not_sql_where1)");
402 $sth_not = $dbh->prepare("select distinct m1.bibid from $not_sql_tables where $not_sql_where1");
409 while(my $bibid = $sth_not->fetchrow()) {
410 $not_bibids{$bibid} = 1; # populates the hashtable with the bibids matching the NOT statement
413 foreach my $bibid (@tmpresult)
415 if(!$not_bibids{$bibid})
417 push @result, $bibid;
423 else # no NOT statements
425 while (my ($bibid) = $sth->fetchrow) {
430 # we have bibid list. Now, loads title and author from [offset] to [offset]+[length]
431 my $counter = $offset;
432 # HINT : biblionumber as bn is important. The hash is fills biblionumber with items.biblionumber.
433 # so if you dont' has an item, you get a not nice empty value.
434 $sth = $dbh->prepare("SELECT biblio.biblionumber as bn,biblio.*, biblioitems.*,marc_biblio.bibid,itemtypes.notforloan,itemtypes.description
435 FROM biblio, marc_biblio
436 LEFT JOIN biblioitems on biblio.biblionumber = biblioitems.biblionumber
437 LEFT JOIN itemtypes on itemtypes.itemtype=biblioitems.itemtype
438 WHERE biblio.biblionumber = marc_biblio.biblionumber AND bibid = ?");
439 my $sth_subtitle = $dbh->prepare("SELECT subtitle FROM bibliosubtitle WHERE biblionumber=?"); # Added BY JF for Subtitles
440 my @finalresult = ();
444 my ($oldbibid, $oldauthor, $oldtitle);
445 my $sth_itemCN = $dbh->prepare("select items.* from items where biblionumber=?");
446 my $sth_issue = $dbh->prepare("select date_due,returndate from issues where itemnumber=?");
447 # parse all biblios between start & end.
448 while (($counter <= $#result) && ($counter <= ($offset + $length))) {
449 # search & parse all items & note itemcallnumber
450 $sth->execute($result[$counter]);
452 my $line = $sth->fetchrow_hashref;
453 my $biblionumber=$line->{bn};
454 # Return subtitles first ADDED BY JF
455 $sth_subtitle->execute($biblionumber);
456 my $subtitle_here.= $sth_subtitle->fetchrow." ";
458 $subtitle = $subtitle_here;
459 # warn "Here's the Biblionumber ".$biblionumber;
460 # warn "and here's the subtitle: ".$subtitle_here;
464 # $continue=0 unless $line->{bn};
465 # my $lastitemnumber;
466 $sth_itemCN->execute($biblionumber);
468 my $notforloan=1; # to see if there is at least 1 item that can be issued
469 while (my $item = $sth_itemCN->fetchrow_hashref) {
470 # parse the result, putting holdingbranch & itemcallnumber in separate array
471 # then all other fields in the main array
473 # search if item is on loan
475 $sth_issue->execute($item->{itemnumber});
476 while (my $loan = $sth_issue->fetchrow_hashref) {
477 if ($loan->{date_due} and !$loan->{returndate}) {
478 $date_due = $loan->{date_due};
483 $lineCN{holdingbranch} = $item->{holdingbranch};
484 $lineCN{itemcallnumber} = $item->{itemcallnumber};
485 $lineCN{location} = $item->{location};
486 $lineCN{date_due} = format_date($date_due);
487 $lineCN{notforloan} = $notforloanstatus{$line->{notforloan}} if ($line->{notforloan}); # setting not forloan if itemtype is not for loan
488 $lineCN{notforloan} = $notforloanstatus{$item->{notforloan}} if ($item->{notforloan}); # setting not forloan it this item is not for loan
489 $notforloan=0 unless ($item->{notforloan} or $item->{wthdrawn} or $item->{itemlost});
490 push @CNresults,\%lineCN;
493 # save the biblio in the final array, with item and item issue status
496 $newline{totitem} = $totalitems;
497 # if $totalitems == 0, check if it's being ordered.
498 if ($totalitems == 0) {
499 my $sth = $dbh->prepare("select count(*) from aqorders where biblionumber=? and datecancellationprinted is NULL");
500 $sth->execute($biblionumber);
501 my ($ordered) = $sth->fetchrow;
502 $newline{onorder} = 1 if $ordered;
504 $newline{biblionumber} = $biblionumber;
505 $newline{norequests} = 0;
506 $newline{norequests} = 1 if ($line->{notforloan}); # itemtype not issuable
507 $newline{norequests} = 1 if (!$line->{notforloan} && $notforloan); # itemtype issuable but all items not issuable for instance
508 $newline{subtitle} = $subtitle; # put the subtitle in ADDED BY JF
510 my @CNresults2= @CNresults;
511 $newline{CN} = \@CNresults2;
512 $newline{'even'} = 1 if $#finalresult % 2 == 0;
513 $newline{'odd'} = 1 if $#finalresult % 2 == 1;
514 $newline{'timestamp'} = format_date($newline{timestamp});
516 push @finalresult, \%newline;
520 my $nbresults = $#result+1;
521 return (\@finalresult, $nbresults);
524 # Creates the SQL Request
527 my ($dbh,$tags, $and_or, $operator, $value) = @_;
529 my $sql_tables; # will contain marc_subfield_table as m1,...
530 my $sql_where1; # will contain the "true" where
531 my $sql_where2 = "("; # will contain m1.bibid=m2.bibid
532 my $nb_active=0; # will contain the number of "active" entries. an entry is active if a value is provided.
533 my $nb_table=1; # will contain the number of table. ++ on each entry EXCEPT when an OR is provided.
535 my $maxloop=8; # the maximum number of words to avoid a too complex search.
536 $maxloop = @$value if @$value<$maxloop;
538 for(my $i=0; $i<=$maxloop;$i++) {
542 if (@$operator[$i] eq "start") {
543 $sql_tables .= "marc_subfield_table as m$nb_table,";
544 $sql_where1 .= "(m1.subfieldvalue like ".$dbh->quote("@$value[$i]%");
546 $sql_where1 .=" and concat(m1.tag,m1.subfieldcode) in (@$tags[$i])";
549 } elsif (@$operator[$i] eq "contains") {
550 $sql_tables .= "marc_word as m$nb_table,";
551 $sql_where1 .= "(m1.word like ".$dbh->quote("@$value[$i]");
553 $sql_where1 .=" and m1.tagsubfield in (@$tags[$i])";
557 $sql_tables .= "marc_subfield_table as m$nb_table,";
558 $sql_where1 .= "(m1.subfieldvalue @$operator[$i] ".$dbh->quote("@$value[$i]");
560 $sql_where1 .=" and concat(m1.tag,m1.subfieldcode) in (@$tags[$i])";
565 if (@$operator[$i] eq "start") {
567 $sql_tables .= "marc_subfield_table as m$nb_table,";
568 $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue like ".$dbh->quote("@$value[$i]%");
570 $sql_where1 .=" and concat(m$nb_table.tag,m$nb_table.subfieldcode) in (@$tags[$i])";
573 $sql_where2 .= "m1.bibid=m$nb_table.bibid and ";
574 } elsif (@$operator[$i] eq "contains") {
575 if (@$and_or[$i] eq 'and') {
577 $sql_tables .= "marc_word as m$nb_table,";
578 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]");
580 $sql_where1 .=" and m$nb_table.tagsubfield in(@$tags[$i])";
583 $sql_where2 .= "m1.bibid=m$nb_table.bibid and ";
585 $sql_where1 .= "@$and_or[$i] (m$nb_table.word like ".$dbh->quote("@$value[$i]");
587 $sql_where1 .=" and m$nb_table.tagsubfield in (@$tags[$i])";
590 $sql_where2 .= "m1.bibid=m$nb_table.bibid and ";
594 $sql_tables .= "marc_subfield_table as m$nb_table,";
595 $sql_where1 .= "@$and_or[$i] (m$nb_table.subfieldvalue @$operator[$i] ".$dbh->quote(@$value[$i]);
597 $sql_where1 .=" and concat(m$nb_table.tag,m$nb_table.subfieldcode) in (@$tags[$i])";
599 $sql_where2 .= "m1.bibid=m$nb_table.bibid and ";
606 if($sql_where2 ne "(") # some datas added to sql_where2, processing
608 $sql_where2 = substr($sql_where2, 0, (length($sql_where2)-5)); # deletes the trailing ' and '
611 else # no sql_where2 statement, deleting '('
615 chop $sql_tables; # deletes the trailing ','
616 return ($sql_tables, $sql_where1, $sql_where2);
620 my ($dbh, $bibid, $marcflavour) = @_;
621 my ($mintag, $maxtag);
622 if ($marcflavour eq "MARC21") {
625 } else { # assume unimarc if not marc21
630 my $sth=$dbh->prepare("SELECT subfieldvalue,tag FROM marc_subfield_table WHERE bibid=? AND tag BETWEEN ? AND ? ORDER BY tagorder");
632 $sth->execute($bibid,$mintag,$maxtag);
639 while (my $data=$sth->fetchrow_arrayref) {
640 my $value=$data->[0];
641 my $thistag=$data->[1];
645 if ($thistag ne $tag && $note ne "") {
646 $marcnote = {marcnote => $note,};
647 push @marcnotes, $marcnote;
651 if ($note ne $value) {
652 $note = $note." ".$value;
657 $marcnote = {marcnote => $note};
658 push @marcnotes, $marcnote; #load last tag into array
664 my $marcnotesarray=\@marcnotes;
665 return $marcnotesarray;
669 sub getMARCsubjects {
670 my ($dbh, $bibid, $marcflavour) = @_;
671 my ($mintag, $maxtag);
672 if ($marcflavour eq "MARC21") {
675 } else { # assume unimarc if not marc21
679 my $sth=$dbh->prepare("SELECT subfieldvalue,subfieldcode FROM marc_subfield_table WHERE bibid=? AND tag BETWEEN ? AND ? ORDER BY tagorder");
681 $sth->execute($bibid,$mintag,$maxtag);
688 while (my $data=$sth->fetchrow_arrayref) {
689 my $value = $data->[0];
690 my $subfield = $data->[1];
691 if ($subfield eq "a" && $value ne $subjct) {
692 $marcsubjct = {MARCSUBJCT => $value,};
693 push @marcsubjcts, $marcsubjct;
701 my $marcsubjctsarray=\@marcsubjcts;
702 return $marcsubjctsarray;
703 } #end getMARCsubjects
705 END { } # module clean-up code here (global destructor)
714 Koha Developement team <info@koha.org>