Laravel查询生成器:带IF语句的DB :: raw给出错误结果

时间:2019-04-02 22:55:03

标签: mysql laravel if-statement

我有一个在mysql中有效的查询,但是在laravel中执行时,我得到了错误的结果。 更新:Laravel版本为4.2。

该查询会检索所有图书,但如果一本书具有“ visibility_school”(布尔值),则当前用户所在的学校必须与图书作者所在的学校相匹配-因此我为此使用了IF语句。

mysql 查询的工作原理是:(请参见WHERE IF行,我在其中硬编码了一个值2(schools.id = 2)以进行比较以进行测试,通常它是动态的)

SELECT book.*, user.name AS name, user.school_class AS schoolClass, schools.name as 
       schoolName, count(DISTINCT book.id) AS overallCount, 
       AVG(book_rating.mark) AS rating 
FROM book
LEFT JOIN user ON book.user_id = user.id
LEFT JOIN book_tag ON book.id = book_tag.book_id
LEFT JOIN book_rating ON book.id = book_rating.book_id
LEFT JOIN schools ON schools.id = user.school_id
WHERE IF(book.visibility_school = 1, IF(schools.id = 2, 1, 0), 1) = 1       
AND book.published = 1                      
AND book.deleted = 0                 
GROUP BY book.id

Laravel查询构建器中执行此操作时,我的代码如下:

$books = DB::table('book')
   ->select(DB::raw("book.*, user.name AS name, user.school_class AS schoolClass, 
               schools.name as schoolName,count(DISTINCT book.id) AS overallCount, 
               AVG(book_rating.mark) AS rating"))
->leftJoin('user', 'book.user_id', '=', 'user.id') 
->leftJoin('book_tag', 'book.id', '=', 'book_tag.book_id')    
->leftJoin('book_rating', 'book.id', '=', 'book_rating.book_id')    
->leftJoin('schools', 'schools.id', '=', 'user.school_id')  
->where(DB::raw("IF(book.visibility_school = 1, IF(schools.id = '?', 1, 0), 1) = 1"),$currentUserSchoolId)
->where('book.published',Book::STATUS_PUBLISHED)
->where('book.deleted',0) 
->groupBy('book.id');

mysql查询正确返回5本书,如果我设置schools.id = 3,则还包括一本只对特定学校ID成员可见的额外书。

但是laravel代码不返回任何书,只有两个例外:

  1. 如果我设置schools.id = 0,我将得到1个结果,该书仅对某所学校的成员可见(应该是ID 3)。

  2. 如果我设置schools.id = 1-我会得到5本书。如果我设置了其他ID,则不会得到任何结果。

如果将$currentUserSchoolId放在数组[$currentUserSchoolId]中,则没有区别。 此外,Book::STATUS_PUBLISHED属性等于1,因此那里的mysql代码版本没有差异。

因此,laravel似乎将where if不是1的情况下,将“ visibility_school”行评估为 false

---------更新---------

提出建议后,我更改了where if行(并添加到该行:AND schools.id <> 0):

->where(DB::raw("book.visibility_school <> 1 OR schools.id = '?' AND schools.id <> 0"), 
      $currentUserSchoolId)

现在我总是可以得到出版的书,所以很好,但是我仍然无法使该书对匹配的学校ID可见。如果我设置了schools.id = 3,我应该得到它,它仍然可以在mysql中工作。但是,如果我将其设置为0(并删除AND school.id <> 0),我也会得到这本书-因此laravel认为出于某种原因,学校ID为0。这就是我目前的问题。

2 个答案:

答案 0 :(得分:0)

您是否有任何理由没有利用the ORM provided by Laravel的优势?

relationships中设置好所有models后,您应该使用以下代码获得大致相同的结果:

MyController.php

$currentUserId = Auth::id();
$books = Book::with(['tag', 'rating', 'user', 'user.school' => function ($query) {
        $query->selectRaw('name as schoolName')->addSelect('id');
    }])
    ->whereHas('user', function ($query) use ($currentUserId) {
        $query->where('id', $currentUserId);
    })
    ->where('published', Book::STATUS_PUBLISHED)
    ->where('visibility_school', true)
    ->where('deleted', false)
    ->get();
}

答案 1 :(得分:0)

使用参数绑定时,您不需要在引号周围使用引号,因此?而不是'?'

DB::raw("IF(book.visibility_school = 1, IF(schools.id = ?, 1, 0), 1) = 1"),$currentUserSchoolId)

但是,正如其他人所建议的那样,可以使用常规和/或操作简化检查