查询语言.join

Testing Is Documentation

tests/Database/Query/JoinTest.php查询语言.join - 图1

join 函数原型

  1. join($table, $cols, ...$cond);
  • 其中 $table 和 $cols 与 《查询语言.table》中的用法一致。
  • $cond 与《查询语言.where》中的用法一致。

Uses

  1. <?php
  2. use Leevel\Database\Condition;
  3. use Tests\Database\DatabaseTestCase as TestCase;

join 基础用法

  1. public function testBaseUse(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`test_query_subsql`.`name`,`test_query_subsql`.`value` FROM `test_query` INNER JOIN `test_query_subsql` ON `test_query_subsql`.`name` = :test_query_subsql_name",
  7. {
  8. "test_query_subsql_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->join('test_query_subsql', 'name,value', 'name', '=', '小牛')
  21. ->findAll(true)
  22. )
  23. );
  24. }

join 附加条件

  1. public function testWithCondition(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` INNER JOIN `test_query_subsql` `t` ON `t`.`name` = :t_name",
  7. {
  8. "t_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->join(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  21. ->findAll(true),
  22. 1
  23. )
  24. );
  25. }

join 附加条件支持数组和表达式

实质上 where 支持语法特性都支持。

  1. public function testWithConditionSupportArrayAndExpression(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`test_query_subsql`.`name`,`test_query_subsql`.`value` FROM `test_query` INNER JOIN `test_query_subsql` ON `test_query_subsql`.`hello` = :test_query_subsql_hello AND `test_query_subsql`.`test` > `test_query_subsql`.`name`",
  7. {
  8. "test_query_subsql_hello": [
  9. "world"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->join('test_query_subsql', 'name,value', ['hello' => 'world', ['test', '>', Condition::raw('[name]')]])
  21. ->findAll(true),
  22. 2
  23. )
  24. );
  25. }

join 附加条件支持闭包

  1. public function testWithConditionIsClosure(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`test_query_subsql`.`name`,`test_query_subsql`.`value` FROM `test_query` INNER JOIN `test_query_subsql` ON (`test_query_subsql`.`id` < :test_query_subsql_id AND `test_query_subsql`.`name` LIKE :test_query_subsql_name)",
  7. {
  8. "test_query_subsql_id": [
  9. 5
  10. ],
  11. "test_query_subsql_name": [
  12. "hello"
  13. ]
  14. },
  15. false
  16. ]
  17. eot;
  18. $this->assertSame(
  19. $sql,
  20. $this->varJson(
  21. $connect
  22. ->table('test_query')
  23. ->join('test_query_subsql', 'name,value', function ($select) {
  24. $select
  25. ->where('id', '<', 5)
  26. ->where('name', 'like', 'hello');
  27. })
  28. ->findAll(true),
  29. 3
  30. )
  31. );
  32. }

innerJoin 查询

  1. public function testInnerJoin(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` INNER JOIN `test_query_subsql` `t` ON `t`.`name` = :t_name",
  7. {
  8. "t_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->innerJoin(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  21. ->findAll(true)
  22. )
  23. );
  24. }

leftJoin 查询

  1. public function testLeftJoin(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` LEFT JOIN `test_query_subsql` `t` ON `t`.`name` = :t_name",
  7. {
  8. "t_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->leftJoin(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  21. ->findAll(true)
  22. )
  23. );
  24. }

rightJoin 查询

  1. public function testRightJoin(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` RIGHT JOIN `test_query_subsql` `t` ON `t`.`name` = :t_name",
  7. {
  8. "t_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->rightJoin(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  21. ->findAll(true)
  22. )
  23. );
  24. }

fullJoin 查询

  1. public function testFullJoin(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` FULL JOIN `test_query_subsql` `t` ON `t`.`name` = :t_name",
  7. {
  8. "t_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->fullJoin(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  21. ->findAll(true)
  22. )
  23. );
  24. }

TIP

MySQL 不支持 FULL JOIN,仅示例。

crossJoin 查询

自然连接不用设置 on 条件。

  1. public function testCrossJoin(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` CROSS JOIN `test_query_subsql` `t`",
  7. [],
  8. false
  9. ]
  10. eot;
  11. $this->assertSame(
  12. $sql,
  13. $this->varJson(
  14. $connect
  15. ->table('test_query')
  16. ->crossJoin(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'])
  17. ->findAll(true)
  18. )
  19. );
  20. }

naturalJoin 查询

自然连接不用设置 on 条件。

  1. public function testNaturalJoin(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`t`.`name` AS `nikename`,`t`.`value` AS `tt` FROM `test_query` NATURAL JOIN `test_query_subsql` `t`",
  7. [],
  8. false
  9. ]
  10. eot;
  11. $this->assertSame(
  12. $sql,
  13. $this->varJson(
  14. $connect
  15. ->table('test_query')
  16. ->naturalJoin(['t' => 'test_query_subsql'], ['name as nikename', 'tt' => 'value'])
  17. ->findAll(true)
  18. )
  19. );
  20. }

join 查询支持表支持查询对象

  1. public function testInnerJoinWithTableIsSelect(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`b`.`name` AS `nikename`,`b`.`value` AS `tt` FROM `test_query` INNER JOIN (SELECT `b`.* FROM `test_query_subsql` `b`) b ON `b`.`name` = :b_name",
  7. {
  8. "b_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $joinTable = $connect->table('test_query_subsql as b');
  16. $this->assertSame(
  17. $sql,
  18. $this->varJson(
  19. $connect
  20. ->table('test_query')
  21. ->innerJoin($joinTable, ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  22. ->findAll(true)
  23. )
  24. );
  25. }

join 查询支持表支持查询条件对象

  1. public function testInnerJoinWithTableIsCondition(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`b`.`name` AS `nikename`,`b`.`value` AS `tt` FROM `test_query` INNER JOIN (SELECT `b`.* FROM `test_query_subsql` `b`) b ON `b`.`name` = :b_name",
  7. {
  8. "b_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $joinTable = $connect
  16. ->table('test_query_subsql as b')
  17. ->databaseCondition();
  18. $this->assertSame(
  19. $sql,
  20. $this->varJson(
  21. $connect
  22. ->table('test_query')
  23. ->innerJoin($joinTable, ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  24. ->findAll(true)
  25. )
  26. );
  27. }

join 查询支持表支持闭包

  1. public function testInnerJoinWithTableIsClosure(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`b`.`name` AS `nikename`,`b`.`value` AS `tt` FROM `test_query` INNER JOIN (SELECT `b`.* FROM `test_query_subsql` `b`) b ON `b`.`name` = :b_name",
  7. {
  8. "b_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $this->assertSame(
  16. $sql,
  17. $this->varJson(
  18. $connect
  19. ->table('test_query')
  20. ->innerJoin(function ($select) {
  21. $select->table('test_query_subsql as b');
  22. }, ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  23. ->findAll(true)
  24. )
  25. );
  26. }

join 查询支持表支持数组别名

  1. public function testInnerJoinWithTableIsArrayCondition(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`foo`.`name` AS `nikename`,`foo`.`value` AS `tt` FROM `test_query` INNER JOIN (SELECT `b`.* FROM `test_query_subsql` `b`) foo ON `foo`.`name` = :foo_name",
  7. {
  8. "foo_name": [
  9. "小牛"
  10. ]
  11. },
  12. false
  13. ]
  14. eot;
  15. $joinTable = $connect
  16. ->table('test_query_subsql as b')
  17. ->databaseCondition();
  18. $this->assertSame(
  19. $sql,
  20. $this->varJson(
  21. $connect
  22. ->table('test_query')
  23. ->innerJoin(['foo' => $joinTable], ['name as nikename', 'tt' => 'value'], 'name', '=', '小牛')
  24. ->findAll(true)
  25. )
  26. );
  27. }

join 查询支持表支持表达式

  1. public function testInnerJsonWithTableNameIsExpression(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`a`.`name` AS `nikename`,`a`.`value` AS `tt` FROM `test_query` INNER JOIN (SELECT * FROM test_query_subsql) a ON `a`.`name` = `test_query`.`name`",
  7. [],
  8. false
  9. ]
  10. eot;
  11. $this->assertSame(
  12. $sql,
  13. $this->varJson(
  14. $connect
  15. ->table('test_query')
  16. ->innerJoin('(SELECT * FROM test_query_subsql)', ['name as nikename', 'tt' => 'value'], 'name', '=', Condition::raw('[test_query.name]'))
  17. ->findAll(true)
  18. )
  19. );
  20. }

join 查询支持表支持表达式别名

  1. public function testInnerJsonWithTableNameIsExpressionWithAsCustomAlias(): void
  2. {
  3. $connect = $this->createDatabaseConnectMock();
  4. $sql = <<<'eot'
  5. [
  6. "SELECT `test_query`.*,`bar`.`name` AS `nikename`,`bar`.`value` AS `tt` FROM `test_query` INNER JOIN (SELECT * FROM test_query_subsql) bar ON `bar`.`name` = `test_query`.`name`",
  7. [],
  8. false
  9. ]
  10. eot;
  11. $this->assertSame(
  12. $sql,
  13. $this->varJson(
  14. $connect
  15. ->table('test_query')
  16. ->innerJoin('(SELECT * FROM test_query_subsql) as bar', ['name as nikename', 'tt' => 'value'], 'name', '=', Condition::raw('[test_query.name]'))
  17. ->findAll(true)
  18. )
  19. );
  20. }