2010-01-20 6 views
2

Je suis en train d'exécuter la requête suivante dans SQLite 3:Problème avec SQLite SQL Query

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
HAVING "distance" <= ? 
ORDER BY "distance" ASC; 

Mais je reçois l'erreur suivante:

SQLSTATE[HY000]: General error: 1 a GROUP BY clause is required before HAVING

Je ne comprends pas pourquoi SQLite veut moi aux résultats du groupe, mais j'essayé ce qui suit:

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
GROUP BY "id" 
HAVING "distance" <= ? 
ORDER BY "distance" ASC; 

Et j'ai aussi essayé ceci:

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
GROUP BY "distance" 
HAVING "distance" <= ? 
ORDER BY "distance" ASC; 

Aucune erreur, mais tous les enregistrements ont été renvoyés (même ceux ayant "distance" > ?). J'ai également essayé de faire:

SELECT *, 
    DISTANCE(latitude, longitude, ?, ?) AS "distance" 
FROM "country" 
WHERE "id" NOT LIKE ? 
    AND "distance" <= ? 
ORDER BY "distance" ASC; 

La même sortie, tous les enregistrements ont été retournés. J'ai vérifié - la distance est calculée correctement ... Je n'ai aucune idée de ce qui ne va pas avec cette requête, quelqu'un peut-il m'aider?

Répondre

2

Vous ne pouvez pas spécifier une clause HAVING sans avoir spécifié une clause GROUP BY. Utilisation:

SELECT *, 
     DISTANCE(latitude, longitude, ?, ?) AS dist 
    FROM COUNTRY c 
    WHERE c.id NOT LIKE ? 
    AND DISTANCE(c.latitude, c.longitude, ?, ?) <= ? 
ORDER BY dist; 

Si vous ne voulez pas appeler DISTANCE plus d'une fois, vous pouvez utiliser une sous-requête:

SELECT x.* 
    FROM (SELECT c.*, 
       DISTANCE(latitude, longitude, ?, ?) AS dist 
      FROM COUNTRY c 
      WHERE c.id NOT LIKE ?) x 
    WHERE x.dist <= ? 
ORDER BY dist; 
+0

Mais j'ai essayé de spécifier une clause 'GROUP BY' ... Est-il possible de lancer la requête sans avoir à appeler deux fois la fonction' DISTANCE'? Cela rendrait la requête beaucoup plus rapide. –

+0

Hummm ... Je ne suis pas non plus un grand fan des requêtes imbriquées, la page 8 de http://www.arubin.org/files/geo_search.pdf est beaucoup plus simple. MySQL Manual (http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html) dit "Le standard SQL n'autorise pas la clause HAVING à nommer une colonne qui n'est pas trouvée dans la clause GROUP BY si elle n'est pas incluse dans une fonction d'agrégation ". Est-ce spécifique à SQLite? Désolé d'être un PITA mais d'une autre façon de contourner ce problème? –

+0

@Alix: Il n'y a pas d'autres options pour minimiser le nombre de fois que vous utilisez 'DISTANCE'. 'DISTANCE' n'est pas une fonction d'agrégat, donc la comparaison appartient à la clause' WHERE'. La seule raison d'utiliser 'HAVING' est parce que vous regroupez des enregistrements - ce qui est peu probable pour une table de pays. –

0

il est erreur de syntaxe, vous devez utiliser « groupe par » lorsque vous utilisez ayant cause

votre requête avec le groupe par est aller chercher des documents ayant (« distance »>) parce que, il y a la règle de base de données cela tout d'abord il prend des données avec des enregistrements correspondants alors il effectuera un groupe par dessus après il est en train de filtrer des enregistrements en ayant cause. de sorte que vous ne recevez jamais les données ayant (« distance » <)

s'il vous plaît corriger si je me trompe

+0

Merci, je ne savais pas que. Est-il possible de réécrire la requête de sorte qu'elle ne renvoie que les enregistrements ayant 'distance <=?' Sans avoir à appeler deux fois la fonction 'DISTANCE'? –

1

Une meilleure approche (et plus rapide) pourrait être de réduire l'ensemble vers le bas SELECTIONNES avant d'appliquer l'ORDRE PAR. J'utilise ce type d'approche:

SELECT * FROM endroits où abs (Latitude - 51,123) < 0,12 ET abs (Longitude - 0,123) < 0,34 ORDER BY DISTANCE (latitude, longitude, 51,123, 0,123)

. ..where (51.123, 0.123) est le centre de latitude/longitude que vous recherchez, et les valeurs de 0.12 et 0.34 sont utilisées pour affiner votre recherche à un lat/long carré sur une sphère d'un taille appropriée (c'est-à-dire un carré de n kilomètres par n kilomètres à ce point de la sphère terrestre, dont la taille dépend de la distribution géographique moyenne de vos emplacements). J'utilise les formules de longueur de degré de http://en.wikipedia.org/wiki/Longitude pour déterminer quelles valeurs devraient être attribuées à la position du point de recherche sur la sphère terrestre.

+0

Merci. Je fais ça, je n'ai pas posté pour éviter d'ajouter trop de fouillis. =) –

-2

Suite à la bonne réponse ci-dessus battant pavillon, si vous ne voulez pas appeler la fonction DISTANCE deux fois, reportez-vous à l'alias dans la clause WHERE, i.e.:

SELECT *, 
     DISTANCE(latitude, longitude, ?, ?) AS dist 
    FROM COUNTRY c 
    WHERE c.id NOT LIKE ? 
    AND dist <= ? 
ORDER BY dist; 
+0

Regardez le dernier extrait de code de ma question ... –