Jak utworzyć wielokrotne zapytanie klauzulowe przy użyciu Laravel Eloquent?

405

Używam konstruktora zapytań Laravel Eloquent i mam zapytanie, w którym chcę WHEREklauzulę dotyczącą wielu warunków. Działa, ale nie jest elegancki.

Przykład:

$results = User::where('this', '=', 1)
    ->where('that', '=', 1)
    ->where('this_too', '=', 1)
    ->where('that_too', '=', 1)
    ->where('this_as_well', '=', 1)
    ->where('that_as_well', '=', 1)
    ->where('this_one_too', '=', 1)
    ->where('that_one_too', '=', 1)
    ->where('this_one_as_well', '=', 1)
    ->where('that_one_as_well', '=', 1)
    ->get();

Czy jest na to lepszy sposób, czy powinienem trzymać się tej metody?

veksen
źródło
4
Istnieje wiele możliwości, w jaki sposób można to uprościć, ale wymagałoby to bardziej realistycznego kodu. Czy możesz zaktualizować kod, aby był trochę bardziej realistyczny? Na przykład zdarza się, że wiele ->where(...)połączeń można zastąpić ->whereIn(...)połączeniem itd .
jonathanmarvens,
1
Zgadzam się, że rozwiązanie @Jarek Tkaczyk powinno być odpowiedzią. Ale wolę twój kod jak skrypt konstruktora do zrozumienia i konserwacji.
Tiefan Ju

Odpowiedzi:

618

W Laravel 5.3 (i wciąż prawdziwy od wersji 7.x ) możesz użyć bardziej szczegółowego ciągu, który jest przekazywany jako tablica:

$query->where([
    ['column_1', '=', 'value_1'],
    ['column_2', '<>', 'value_2'],
    [COLUMN, OPERATOR, VALUE],
    ...
])

Osobiście nie znalazłem przypadku użycia tylko dla wielu wherepołączeń, ale faktem jest, że możesz go użyć.

Od czerwca 2014 r. Możesz przekazać tablicę do where

Tak długo, jak chcesz wszystkie operator wheresużycia and, możesz pogrupować je w ten sposób:

$matchThese = ['field' => 'value', 'another_field' => 'another_value', ...];

// if you need another group of wheres as an alternative:
$orThose = ['yet_another_field' => 'yet_another_value', ...];

Następnie:

$results = User::where($matchThese)->get();

// with another group
$results = User::where($matchThese)
    ->orWhere($orThose)
    ->get();

Powyższe spowoduje takie zapytanie:

SELECT * FROM users
  WHERE (field = value AND another_field = another_value AND ...)
  OR (yet_another_field = yet_another_value AND ...)
Jarek Tkaczyk
źródło
8
Jak określasz operatora?
Styphon
9
@Styphon Nie. Obecnie działa tylko z =.
Jarek Tkaczyk
5
@Styphon a co jeśli chcę zrobić: WHERE (a IS NOT NULL AND b=1) OR (a IS NULL AND b=2);?
alexglue
9
Możesz także przekazać tablicę takich warunków:$users = DB::table('users')->where([ ['status', '=', '1'], ['subscribed', '<>', '1'], ])->get();
zera i
3
@jarek: Jak dołączyć whereNotInzgodnie z twoją odpowiedzią, mając inne wherecluazy?
Kalanka
93

Zakresy zapytań mogą pomóc w zwiększeniu czytelności kodu.

http://laravel.com/docs/eloquent#query-scopes

Aktualizacja tej odpowiedzi za pomocą jakiegoś przykładu:

W swoim modelu utwórz metody zakresów takie jak to:

public function scopeActive($query)
{
    return $query->where('active', '=', 1);
}

public function scopeThat($query)
{
    return $query->where('that', '=', 1);
}

Następnie możesz wywołać ten zakres podczas budowania zapytania:

$users = User::active()->that()->get();
Luis Dalmolin
źródło
jaka jest najlepsza praktyka w przypadku takiego stanu, zapytanie-> gdzie ('data_początkowa>> $ data_początkowa) nadal można używać zakresów?
Buwaneka Kalansuriya
72

Możesz użyć podkwerend w funkcji anonimowej, takiej jak ta:

 $results = User::where('this', '=', 1)
            ->where('that', '=', 1)
            ->where(function($query) {
                /** @var $query Illuminate\Database\Query\Builder  */
                return $query->where('this_too', 'LIKE', '%fake%')
                    ->orWhere('that_too', '=', 1);
            })
            ->get();
Juljan
źródło
43

W takim przypadku możesz użyć czegoś takiego:

User::where('this', '=', 1)
    ->whereNotNull('created_at')
    ->whereNotNull('updated_at')
    ->where(function($query){
        return $query
        ->whereNull('alias')
        ->orWhere('alias', '=', 'admin');
    });

Powinien dostarczyć Ci zapytanie takie jak:

SELECT * FROM `user` 
WHERE `user`.`this` = 1 
    AND `user`.`created_at` IS NOT NULL 
    AND `user`.`updated_at` IS NOT NULL 
    AND (`alias` IS NULL OR `alias` = 'admin')
alexglue
źródło
36

Warunki korzystania z macierzy:

$users = User::where([
       'column1' => value1,
       'column2' => value2,
       'column3' => value3
])->get();

Wytworzy zapytanie jak poniżej:

SELECT * FROM TABLE WHERE column1=value1 and column2=value2 and column3=value3

Warunki korzystania z funkcji anonimowej:

$users = User::where('column1', '=', value1)
               ->where(function($query) use ($variable1,$variable2){
                    $query->where('column2','=',$variable1)
                   ->orWhere('column3','=',$variable2);
               })
              ->where(function($query2) use ($variable1,$variable2){
                    $query2->where('column4','=',$variable1)
                   ->where('column5','=',$variable2);
              })->get();

Wytworzy zapytanie jak poniżej:

SELECT * FROM TABLE WHERE column1=value1 and (column2=value2 or column3=value3) and (column4=value4 and column5=value5)
Srmilon
źródło
12

Wiele klauzul where

    $query=DB::table('users')
        ->whereRaw("users.id BETWEEN 1003 AND 1004")
        ->whereNotIn('users.id', [1005,1006,1007])
        ->whereIn('users.id',  [1008,1009,1010]);
    $query->where(function($query2) use ($value)
    {
        $query2->where('user_type', 2)
            ->orWhere('value', $value);
    });

   if ($user == 'admin'){
        $query->where('users.user_name', $user);
    }

wreszcie uzyskam wynik

    $result = $query->get();
Majbah Habib
źródło
9

whereColumnSposób może być przekazywana szereg różnych warunkach. Warunki te zostaną połączone za pomocą andoperatora.

Przykład:

$users = DB::table('users')
            ->whereColumn([
                ['first_name', '=', 'last_name'],
                ['updated_at', '>', 'created_at']
            ])->get();

$users = User::whereColumn([
                ['first_name', '=', 'last_name'],
                ['updated_at', '>', 'created_at']
            ])->get();

Aby uzyskać więcej informacji, sprawdź tę sekcję dokumentacji https://laravel.com/docs/5.4/queries#where-clauses

Alex Quintero
źródło
8
Model::where('column_1','=','value_1')->where('column_2 ','=','value_2')->get();

LUB

// If you are looking for equal value then no need to add =
Model::where('column_1','value_1')->where('column_2','value_2')->get();

LUB

Model::where(['column_1' => 'value_1','column_2' => 'value_2'])->get();
DsRaj
źródło
5

Pamiętaj, aby zastosować wszystkie inne filtry do zapytań podrzędnych, w przeciwnym razie lub może zgromadzić wszystkie rekordy.

$query = Activity::whereNotNull('id');
$count = 0;
foreach ($this->Reporter()->get() as $service) {
        $condition = ($count == 0) ? "where" : "orWhere";
        $query->$condition(function ($query) use ($service) {
            $query->where('branch_id', '=', $service->branch_id)
                  ->where('activity_type_id', '=', $service->activity_type_id)
                  ->whereBetween('activity_date_time', [$this->start_date, $this->end_date]);
        });
    $count++;
}
return $query->get();
Adam
źródło
Dziękujemy za dodanie „use ($ service)”. Odpowiedź Juljana była prawie tym, czego potrzebowałem. Twój komentarz pomógł mi przekazać szukany ciąg do zapytania.
Elliot Robert
5
$projects = DB::table('projects')->where([['title','like','%'.$input.'%'],
    ['status','<>','Pending'],
    ['status','<>','Not Available']])
->orwhere([['owner', 'like', '%'.$input.'%'],
    ['status','<>','Pending'],
    ['status','<>','Not Available']])->get();
Lim Kean Phang
źródło
3

Bez prawdziwego przykładu trudno jest wydać zalecenie. Jednak nigdy nie potrzebowałem używać tylu klauzul WHERE w zapytaniu, co może wskazywać na problem ze strukturą danych.

Pomocne może być poznanie normalizacji danych: http://en.wikipedia.org/wiki/Third_normal_form

Aaron Cicali
źródło
3

Możesz używać elokwentnego w Laravel 5.3

Wszystkie wyniki

UserModel::where('id_user', $id_user)
                ->where('estado', 1)
                ->get();

Częściowe wyniki

UserModel::where('id_user', $id_user)
                    ->where('estado', 1)
                    ->pluck('id_rol');
Cristhian Carreño
źródło
3
Czym różni się to od pytania?
veksen
2

użyj whereInwarunku i przekaż tablicę

$array = [1008,1009,1010];

User::whereIn('users.id', $array)->get();

Rahul Tathod
źródło
1

Możesz użyć tablicy w klauzuli where, jak pokazano poniżej.

$result=DB::table('users')->where(array(
'column1' => value1,
'column2' => value2,
'column3' => value3))
->get();
Abhijeet Navgire
źródło
1
DB::table('users')
            ->where('name', '=', 'John')
            ->orWhere(function ($query) {
                $query->where('votes', '>', 100)
                      ->where('title', '<>', 'Admin');
            })
            ->get();
przepraszam
źródło
1

Zgodnie z moją sugestią, jeśli wykonujesz filtr lub wyszukiwanie

powinieneś iść z:

        $results = User::query();
        $results->when($request->that, function ($q) use ($request) {
            $q->where('that', $request->that);
        });
        $results->when($request->this, function ($q) use ($request) {
            $q->where('this', $request->that);
        });
        $results->when($request->this_too, function ($q) use ($request) {
            $q->where('this_too', $request->that);
        });
        $results->get();
Dhruv Raval
źródło
czy wyszukiwanie odbywa się po stronie phpside czy sql?
Mohamed
Strona Sql. Zapytanie SQL jest wykonywane jako parametr żądania. dawny. jeśli polecenie ma ten parametr. Następnie gdzie to = '' gdzie warunek dodany do zapytania.
Dhruv Raval
1

Użyj tego

$users = DB::table('users')
                    ->where('votes', '>', 100)
                    ->orWhere('name', 'John')
                    ->get();
Sooraj Thekkepatt
źródło
0

Używając czystego Elokwenta, zaimplementuj go w ten sposób. Ten kod zwraca wszystkich zalogowanych użytkowników, których konta są aktywne. $users = \App\User::where('status', 'active')->where('logged_in', true)->get();

Craig GeRa
źródło
0

Próbka kodu.

Po pierwsze :

$matchesLcl=[];

tablica jest wypełniana tutaj za pomocą żądanej liczby / pętli warunków, stopniowo:

if (trim($request->pos) != '') $matchesLcl['pos']= $request->pos;

i tu:

if (trim($operation) !== '')$matchesLcl['operation']= $operation;

i dalej z elokwentami, takimi jak:

if (!empty($matchesLcl))
    $setLcl= MyModel::select(['a', 'b', 'c', 'd'])
        ->where($matchesLcl)
        ->whereBetween('updated_at', array($newStartDate . ' 00:00:00', $newEndDate . ' 23:59:59'));
else 
    $setLcl= MyModel::select(['a', 'b', 'c', 'd'])
        ->whereBetween('updated_at', array($newStartDate . ' 00:00:00', $newEndDate . ' 23:59:59'));
CodeToLife
źródło
-4
public function search()
{
    if (isset($_GET) && !empty($_GET))
    {
        $prepareQuery = '';
        foreach ($_GET as $key => $data)
        {
            if ($data)
            {
                $prepareQuery.=$key . ' = "' . $data . '" OR ';
            }
        }
        $query = substr($prepareQuery, 0, -3);
        if ($query)
            $model = Businesses::whereRaw($query)->get();
        else
            $model = Businesses::get();

        return view('pages.search', compact('model', 'model'));
    }
}
Muhammad Arslan
źródło
Jest to bardzo podatne na wstrzyknięcie SQL.
rrrhys
-21
$variable = array('this' => 1,
                    'that' => 1
                    'that' => 1,
                    'this_too' => 1,
                    'that_too' => 1,
                    'this_as_well' => 1,
                    'that_as_well' => 1,
                    'this_one_too' => 1,
                    'that_one_too' => 1,
                    'this_one_as_well' => 1,
                    'that_one_as_well' => 1);

foreach ($variable as $key => $value) {
    User::where($key, '=', $value);
}
Jurij Lazo
źródło
Spowoduje to wykonanie wielu zapytań.
veksen