2010-08-12 9 views
7

Muszę zbudować zapytanie na podstawie określonych warunków. Czy jest lepszy sposób na zrobienie tego niż sposób, który zrobiłem poniżej? Działa to dobrze, ale widzę, że wymyka się spod kontroli dość szybko, jeśli jest więcej warunków, ponieważ sprawdzam, czy za każdym razem, gdy sprawdzałem nowe, spełniłem wszystkie poprzednie warunki.Budowanie długiej kwerendy i wiele instrukcji if - czy istnieje bardziej elegancki sposób?

$sql = "SELECT DISTINCT fkRespondentID FROM tblRespondentDayTime"; 

    if (!empty($day) || !empty($time) || !empty($sportID)) { 

     $sql .= " WHERE"; 

     if (!empty($day)) { 
      $sql .= " fldDay='$day'"; 
     } 

     if (!empty($time)) { 
      if (!empty($day)) { 
       $sql .= " AND"; 
      } 
      $sql .= " fldTime='$time'"; 
     } 

     if (!empty($sportID)) { 
      if (!empty($day) || !empty($time)) { 
       $sql .= " AND"; 
      } 
      $sql .= " fkRespondentID IN (SELECT fkRespondentID FROM tblRespondentSport WHERE fkSportID='$sportID')"; 
     } 

    } 
+0

To dobre pytanie :) – dmp

Odpowiedz

6

Chciałbym użyć starej sztuczki "WHERE 1=1"; dodaj to jako pierwszy warunek, a następnie możesz założyć warunek "AND" na każdym następnym stwierdzeniu.

+0

@Palpie wykazał praktyczne zastosowanie tej metody w swojej odpowiedzi. – DanP

0

możesz spróbować umieścić swoje zmienne w tablicy i mieć boolean, która mówi, czy musisz dodać "AND" przed następną frazą. Skróciłoby to twoje instrukcje sterujące na foreach i zagnieżdżone, jeśli.

0

Oto moje rozwiązanie:

$sql = "SELECT * FROM table"; 
$conditions = array(
    'fldDay' => $day, 
    'fldTime' => $time, 
); 

if (count(array_filter($conditions))) { 
    $sql .= ' WHERE '; 
    $sql .= implode(' AND ', array_map(function($field, $value) { 
    return $field . '=\'' . pg_escape_string($value) . '\''; 
    }, array_keys($conditions), $conditions)); 
} 

Należy pamiętać, że z powodu zamknięcia, to nie będzie działać pod PHP 5.3. Jeśli używasz starszego PHP, zamknij jako oddzielną funkcję lub zastąp go foreach.

+0

Ten kod jest trudny do odczytania. –

1

Zbuduj listę/tablicę warunków, w której każdy warunek jest opcjonalny (tj. Jeśli warunek jest prawidłowy, należy go nacisnąć na liście).

Jeśli ta lista jest> 0, dodaj "gdzie", a następnie dodaj listę dołączoną przez "i".

0

Niestety, budowanie dynamicznego SQL jest żmudnym doświadczeniem, a nawet jeśli możesz zmienić kilka rzeczy w swojej logice (która wygląda na względnie czystą), to nadal będzie brzydkie. Na przykład Object-relational mapping istnieje. Nie jestem zbyt obeznany z PHP, ale Perl ma kilka modułów CPAN, takich jak SQL :: Abstract, które pozwolą ci budować dość złożone instrukcje SQL przy użyciu podstawowych struktur danych.

+0

Nie znamy rozmiaru systemu, który tworzy birderic. Może zawierać ORM i konstruktory SQL nie są tutaj optymalne. –

1

Zamiast robić kontrole jak if (!empty($day) || !empty($time)) można utworzyć zmienną $whereClause i sprawdzić to w ten sposób:

$sql = "SELECT DISTINCT fkRespondentID 
     FROM tblRespondentDayTime"; 

$whereClause = ''; 

// fldDay 
if (!empty($day)) { 
    $whereClause .= " fldDay='$day'"; 
} 

// fldTime 
if (!empty($time)) { 
    if (!empty($whereClause)) { 
     $whereClause .= ' AND '; 
    } 
    $whereClause .= " fldTime='$time'"; 
} 

// fkRespondentID 
if (!empty($sportID)) { 
    if (!empty($whereClause)) { 
     $whereClause .= ' AND '; 
    } 
    $whereClause .= " fkRespondentID IN (SELECT fkRespondentID 
             FROM tblRespondentSport 
             WHERE fkSportID='$sportID')"; 
} 

if (!empty($whereClause)) { 
    $whereClause = ' WHERE '.$whereClause; 
} 

$sql .= $whereClause; 

To będzie również działać, jeśli trzeba, powiedzmy, zmienić niektóre do OR (1 = 1-trick w tym przypadku nie zadziała, a nawet może okazać się dość niebezpieczny).

4
$sql = "SELECT DISTINCT fkRespondentID FROM tblRespondentDayTime WHERE 1=1"; 

if (!empty($day)) 
    $sql .= "AND fldDay='$day'"; 

if (!empty($time)) { 
    $sql .= "AND fldTime='$time'"; 

if (!empty($sportID)) 
    $sql .= "AND fkRespondentID IN (SELECT fkRespondentID FROM tblRespondentSport WHERE fkSportID='$sportID')"; 
+0

Dzięki za przykładową implementację + 1 – DanP

0

Jeśli używasz procedur przechowywanych, można zrobić coś takiego:

CREATE PROCEDURE `FindRespondents` (
    IN `_day` varchar(255), 
    ... 
) 
BEGIN 
    SELECT DISTINCT fkRespondentID 
    FROM tblRespondentDayTime 
    WHERE (_day Is Null OR fldDay = _day) 
     AND ... 
END; 
| 

przekazując null dla _day oznacza każdą fldDay jest OK. Każda inna wartość dla _day i musi być dopasowana. Zakładam, że fldDay jest tekstem, ale oczywiście możesz wpisać wszystko poprawnie tutaj.

Wiem, że niektórzy ludzie nie są fanami procedur przechowywanych, ale może to być przydatne w tym celu.

+0

Myślę, że działałoby również z przygotowanymi instrukcjami, jeśli napiszesz klauzulę where w ten sposób i powiążesz każdy z tych parametrów z '?' S. – grossvogel

Powiązane problemy