docs: def diff_asymmetric(self, catalogue, prime_label, tokenizer, output_fh):
          """Returns `output_fh` populated with CSV results giving the
          difference in n-grams between the witnesses of labelled sets
          of works in `catalogue`, limited to those works labelled with
          `prime_label`.
  
          :param catalogue: catalogue matching filenames to labels
          :type catalogue: `Catalogue`
          :param prime_label: label to limit results to
          :type prime_label: `str`
          :param tokenizer: tokenizer for the n-grams
          :type tokenizer: `Tokenizer`
          :param output_fh: object to output results to
          :type output_fh: file-like object
          :rtype: file-like object
  
          """
          labels = list(self._set_labels(catalogue))
          if len(labels) < 2:
              raise MalformedQueryError(
                  constants.INSUFFICIENT_LABELS_QUERY_ERROR)
          try:
              labels.remove(prime_label)
          except ValueError:
              raise MalformedQueryError(constants.LABEL_NOT_IN_CATALOGUE_ERROR)
          label_placeholders = self._get_placeholders(labels)
          query = constants.SELECT_DIFF_ASYMMETRIC_SQL.format(label_placeholders)
          parameters = [prime_label, prime_label] + labels
          self._logger.info('Running asymmetric diff query')
          self._logger.debug('Query: {}\nLabels: {}\nPrime label: {}'.format(
              query, labels, prime_label))
          self._log_query_plan(query, parameters)
          cursor = self._conn.execute(query, parameters)
          return self._diff(cursor, tokenizer, output_fh)