Laravel - Union + Paginate at the same time?

后端 未结 12 561
有刺的猬
有刺的猬 2020-12-09 04:20

Brief:

I am trying to union 2 tables recipes and posts then add ->paginate(5) to the queries.

But

12条回答
  •  自闭症患者
    2020-12-09 04:40

    I know this answer is too late. But I want to share my problems and my solution.

    My problems:

    1. Join with many tables at the same time
    2. UNION
    3. Paginate (Must use, because I have to use a common theme to show pagination. If I made own custom for pagination, it will not match to current. And in the future, a common theme may be changed.)
    4. Big data: view took 4 seconds, page load took 4 seconds => total is 8 seconds. (But if I set condition inside that view, it was least than 1 second for total.)

    Query

    ※This is the sample. MariaDB, about 146,000 records.

    SELECT A.a_id
         , A.a_name
         , B.organization_id
         , B.organization_name
      FROM customers A 
        LEFT JOIN organizations B ON (A.organization_id = B.organization_id)
    
    UNION ALL
    
    SELECT A.a_id
         , A.a_name
         , B.organization_id
         , B.organization_name
      FROM employees A 
        LEFT JOIN organizations B ON (A.organization_id = B.organization_id)
    

    Solution

    Reference from www.tech-corgi.com (やり方2), I updated my PHP code to filter inside my query, and then call paginate normally.

    I must add a condition (filter) before getting large records. In this example is organization_id.

    $query = "
        SELECT A.a_id
             , A.a_name
             , B.organization_id
             , B.organization_name
          FROM customers A 
            LEFT JOIN organizations B ON (A.organization_id = B.organization_id)
         WHERE 1 = 1
           AND B.organization_id = {ORGANIZATION_ID}
    
        UNION ALL
    
        SELECT A.a_id
             , A.a_name
             , B.organization_id
             , B.organization_name
          FROM employees A 
            LEFT JOIN organizations B ON (A.organization_id = B.organization_id)
    
         WHERE 1 = 1
           AND B.organization_id = {ORGANIZATION_ID}
    ";
    
    $organization_id = request()->organization_id;
    $query = str_replace("{ORGANIZATION_ID}", $organization_id, $query);
    

    But it still cannot be used in paginate(). There is a trick to solve this problem. See below.

    Final code

    Trick: put query inside (). For example: (SELECT * FROM TABLE_A).

    Reason: paginage() will generate and run Count query SELECT count(*) FROM (SELECT * FROM TABLE_A), if we did not put inside brackets, Count query would not be a correct query.

    $query = "
        ( SELECT A.a_id
             , A.a_name
             , B.organization_id
             , B.organization_name
          FROM customers A 
            LEFT JOIN organizations B ON (A.organization_id = B.organization_id)
         WHERE 1 = 1
           AND B.organization_id = {ORGANIZATION_ID}
    
        UNION ALL
    
        SELECT A.a_id
             , A.a_name
             , B.organization_id
             , B.organization_name
          FROM employees A 
            LEFT JOIN organizations B ON (A.organization_id = B.organization_id)
    
         WHERE 1 = 1
           AND B.organization_id = {ORGANIZATION_ID}
        ) AS VIEW_RESULT
    ";
    
    $organization_id = request()->organization_id;
    $query = str_replace("{ORGANIZATION_ID}", $organization_id, $query);
    
    $resultSet = DB::table(DB::raw($query))->paginate(20);
    

    Now I can use it normally:

    1. SELECT, JOIN, UNION
    2. paginate
    3. High performance: Filter data before getting

    Hope it help!!!

提交回复
热议问题