Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

It is impossible to create relation with "not equal" condition. OnCondition not supports conditions for columns #153

Open
Insolita opened this issue May 14, 2021 · 3 comments
Labels

Comments

@Insolita
Copy link

Insolita commented May 14, 2021

Required query

SELECT "documents".*,"dup".*
FROM "documents"
    LEFT JOIN "documents" "dup"
        ON ("documents"."filehash" = "dup"."filehash"
                AND "documents"."company_id" = "dup"."company_id"
                AND "documents"."id" != "dup"."id"
            )

Try to define a relation in model Document

   public function getDuplicates()
    {
        return $this->hasMany(Document::class, ['filehash' => 'filehash', 'company_id' => 'company_id'])
               ->alias('dup')
            ->onCondition(new Expression('"dup"."id" != "documents"."id"'));

    }

Query

$query = new ActiveQuery(Document::class, $db);
$query->alias('documents')->joinWith('duplicates')->all();

Fails with error

SQLSTATE[42P01]: Undefined table: 7 ERROR: invalid reference to FROM-clause entry for table "documents"
LINE 1: ..._id") IN (($1, $2), ($3, $4))) AND ("dup"."id" != "documents...
^
HINT: Perhaps you meant to reference the table alias "dup".
The SQL being executed was: SELECT * FROM "documents" "dup" WHERE (("filehash", "company_id") IN (('e53d24bd42e888cd7d7824132f1fd5a0c9ed9fe2', 5), ('e53d24bd42e888cd7d7824132f1fd5a0c9ed9fe2', 5))) AND ("dup"."id" != "documents"."id")

But command SQL is OK :

$query = new ActiveQuery(Document::class, $db);
$query->alias('documents')->joinWith('duplicates')->createCommand()->getRawSql();

return
SELECT "documents".* FROM "documents" "documents" LEFT JOIN "documents" "dup" ON ("documents"."filehash" = "dup"."filehash" AND "documents"."company_id" = "dup"."company_id") AND ("dup"."id" != "documents"."id")

The problem comes from ActiveQuery populate

https://github.com/yiisoft/db/blob/master/src/Query/Query.php#L203

https://github.com/yiisoft/active-record/blob/master/src/ActiveQuery.php#L250

$relation->populateRelation($name, $models);

This method replaces values from relation "link" to real values, but it doesn't touch "onCondition" expression,

$attributes = array_keys($this->link);

This method executes wrong query

$models = $this->all();

@darkdef
Copy link
Contributor

darkdef commented May 15, 2021

If we fix you problem - in populate be cyclical relation
For example, for link relation duplicates need be create sql with left join documents, and result query be incorrect (with select fromdocuments & join document)

For your problem - simple add where condition

$query = new ActiveQuery(Document::class, $db);
$query->alias('documents')->joinWith('duplicates')
->andWhere(new Expression('{{dup}}.{{id}} != {{documents}}.{{id}}'))
->all();

And i recommend use for quote {{tableName}}.{{columnName}} - for compatible with other db drivers

@Insolita
Copy link
Author

Insolita commented May 15, 2021

->andWhere(new Expression('{{dup}}.{{id}} != {{documents}}.{{id}}'))

Unfortunately, a result of populated models with this query is not correct and contains duplicated ids in $model->duplicates ;
The valid result will be only if add additional grouping clause and aggregate duplicated records, or ids with array_agg/json_agg into an additional property or another kind of hacks
So, SQL is ok - the problem in the model population

@samdark samdark added the type:bug Bug label May 19, 2021
@Tigrov
Copy link
Member

Tigrov commented Jun 7, 2024

Unfortunately, a result of populated models with this query is not correct and contains duplicated ids in $model->duplicates ; The valid result will be only if add additional grouping clause and aggregate duplicated records, or ids with array_agg/json_agg into an additional property or another kind of hacks So, SQL is ok - the problem in the model population

You can also use indexBy option by unique field or Closure to remove duplicate records.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants