23 QString QgsJoinByAttributeAlgorithm::name()
 const 
   25   return QStringLiteral( 
"joinattributestable" );
 
   28 QString QgsJoinByAttributeAlgorithm::displayName()
 const 
   30   return QObject::tr( 
"Join attributes by field value" );
 
   33 QStringList QgsJoinByAttributeAlgorithm::tags()
 const 
   35   return QObject::tr( 
"join,connect,attributes,values,fields,tables" ).split( 
',' );
 
   38 QString QgsJoinByAttributeAlgorithm::group()
 const 
   40   return QObject::tr( 
"Vector general" );
 
   43 QString QgsJoinByAttributeAlgorithm::groupId()
 const 
   45   return QStringLiteral( 
"vectorgeneral" );
 
   48 void QgsJoinByAttributeAlgorithm::initAlgorithm( 
const QVariantMap & )
 
   51   methods << QObject::tr( 
"Create separate feature for each matching feature (one-to-many)" )
 
   52           << QObject::tr( 
"Take attributes of the first matching feature only (one-to-one)" );
 
   57                 QObject::tr( 
"Table field" ), QVariant(), QStringLiteral( 
"INPUT" ) ) );
 
   62                 QObject::tr( 
"Table field 2" ), QVariant(), QStringLiteral( 
"INPUT_2" ) ) );
 
   65                 QObject::tr( 
"Layer 2 fields to copy (leave empty to copy all fields)" ),
 
   70                 QObject::tr( 
"Join type" ),
 
   71                 methods, 
false, 1 ) );
 
   73                 QObject::tr( 
"Discard records which could not be joined" ),
 
   77                 QObject::tr( 
"Joined field prefix" ), QVariant(), 
false, 
true ) );
 
   81   std::unique_ptr< QgsProcessingParameterFeatureSink > nonMatchingSink = std::make_unique< QgsProcessingParameterFeatureSink >(
 
   85   addParameter( nonMatchingSink.release() );
 
   87   addOutput( 
new QgsProcessingOutputNumber( QStringLiteral( 
"JOINED_COUNT" ), QObject::tr( 
"Number of joined features from input table" ) ) );
 
   88   addOutput( 
new QgsProcessingOutputNumber( QStringLiteral( 
"UNJOINABLE_COUNT" ), QObject::tr( 
"Number of unjoinable features from input table" ) ) );
 
   91 QString QgsJoinByAttributeAlgorithm::shortHelpString()
 const 
   93   return QObject::tr( 
"This algorithm takes an input vector layer and creates a new vector layer that is an extended version of the " 
   94                       "input one, with additional attributes in its attribute table.\n\n" 
   95                       "The additional attributes and their values are taken from a second vector layer. An attribute is selected " 
   96                       "in each of them to define the join criteria." );
 
   99 QgsJoinByAttributeAlgorithm *QgsJoinByAttributeAlgorithm::createInstance()
 const 
  101   return new QgsJoinByAttributeAlgorithm();
 
  106   int joinMethod = parameterAsEnum( parameters, QStringLiteral( 
"METHOD" ), context );
 
  107   bool discardNonMatching = parameterAsBoolean( parameters, QStringLiteral( 
"DISCARD_NONMATCHING" ), context );
 
  109   std::unique_ptr< QgsProcessingFeatureSource > input( parameterAsSource( parameters, QStringLiteral( 
"INPUT" ), context ) );
 
  113   std::unique_ptr< QgsProcessingFeatureSource > input2( parameterAsSource( parameters, QStringLiteral( 
"INPUT_2" ), context ) );
 
  117   QString prefix = parameterAsString( parameters, QStringLiteral( 
"PREFIX" ), context );
 
  119   QString field1Name = parameterAsString( parameters, QStringLiteral( 
"FIELD" ), context );
 
  120   QString field2Name = parameterAsString( parameters, QStringLiteral( 
"FIELD_2" ), context );
 
  121   const QStringList fieldsToCopy = parameterAsFields( parameters, QStringLiteral( 
"FIELDS_TO_COPY" ), context );
 
  123   int joinField1Index = input->fields().lookupField( field1Name );
 
  124   int joinField2Index = input2->fields().lookupField( field2Name );
 
  125   if ( joinField1Index < 0 || joinField2Index < 0 )
 
  130   if ( fieldsToCopy.empty() )
 
  132     outFields2 = input2->fields();
 
  133     fields2Indices.reserve( outFields2.
count() );
 
  134     for ( 
int i = 0; i < outFields2.
count(); ++i )
 
  141     fields2Indices.reserve( fieldsToCopy.count() );
 
  142     for ( 
const QString &
field : fieldsToCopy )
 
  147         fields2Indices << index;
 
  148         outFields2.
append( input2->fields().at( index ) );
 
  153   if ( !prefix.isEmpty() )
 
  155     for ( 
int i = 0; i < outFields2.
count(); ++i )
 
  157       outFields2.
rename( i, prefix + outFields2[ i ].name() );
 
  162   fields2Fetch << joinField2Index;
 
  167   std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( 
"OUTPUT" ), context, dest, outFields,
 
  169   if ( parameters.value( QStringLiteral( 
"OUTPUT" ) ).isValid() && !sink )
 
  172   QString destNonMatching1;
 
  173   std::unique_ptr< QgsFeatureSink > sinkNonMatching1( parameterAsSink( parameters, QStringLiteral( 
"NON_MATCHING" ), context, destNonMatching1, input->fields(),
 
  175   if ( parameters.value( QStringLiteral( 
"NON_MATCHING" ) ).isValid() && !sinkNonMatching1 )
 
  179   QMultiHash< QVariant, QgsAttributes > input2AttributeCache;
 
  181   double step = input2->featureCount() > 0 ? 50.0 / input2->featureCount() : 1;
 
  194     if ( joinMethod == 1 && input2AttributeCache.contains( feat.
attribute( joinField2Index ) ) )
 
  199     for ( 
int j = 0; j < feat.
attributes().count(); ++j )
 
  201       if ( ! fields2Indices.contains( j ) )
 
  206     input2AttributeCache.insert( feat.
attribute( joinField2Index ), attributes );
 
  210   step = input->featureCount() > 0 ? 50.0 / input->featureCount() : 1;
 
  213   long long joinedCount = 0;
 
  214   long long unjoinedCount = 0;
 
  225     if ( input2AttributeCache.count( feat.
attribute( joinField1Index ) ) > 0 )
 
  232         QList< QgsAttributes > attributes = input2AttributeCache.values( feat.
attribute( joinField1Index ) );
 
  233         QList< QgsAttributes >::iterator attrsIt = attributes.begin();
 
  234         for ( ; attrsIt != attributes.end(); ++attrsIt )
 
  237           newAttrs.append( *attrsIt );
 
  246       if ( sink && !discardNonMatching )
 
  250       if ( sinkNonMatching1 )
 
  258   feedback->
pushInfo( QObject::tr( 
"%1 feature(s) from input layer were successfully matched" ).arg( joinedCount ) );
 
  259   if ( unjoinedCount > 0 )
 
  260     feedback->
reportError( QObject::tr( 
"%1 feature(s) from input layer could not be matched" ).arg( unjoinedCount ) );
 
  264     outputs.insert( QStringLiteral( 
"OUTPUT" ), dest );
 
  265   outputs.insert( QStringLiteral( 
"JOINED_COUNT" ), joinedCount );
 
  266   outputs.insert( QStringLiteral( 
"UNJOINABLE_COUNT" ), unjoinedCount );
 
  267   if ( sinkNonMatching1 )
 
  268     outputs.insert( QStringLiteral( 
"NON_MATCHING" ), destNonMatching1 );
 
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
@ RegeneratePrimaryKey
This flag indicates, that a primary key field cannot be guaranteed to be unique and the sink should i...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
void setProgress(double progress)
Sets the current progress for the feedback object.
Container of fields for a vector layer.
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
int count() const
Returns number of items.
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
bool rename(int fieldIdx, const QString &name)
Renames a name of field.
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A numeric output for processing algorithms.
A boolean parameter for processing algorithms.
An enum based parameter for processing algorithms, allowing for selection from predefined values.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A string parameter for processing algorithms.
static QgsFields combineFields(const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix=QString())
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ TypeVectorAnyGeometry
Any vector layer with geometry.
QList< int > QgsAttributeList