2009-02-26 9 views
33

Je dois trouver une instruction select qui retournera soit un enregistrement qui correspond exactement à mon entrée, soit la correspondance la plus proche si aucune correspondance exacte n'est trouvée.Trouver la valeur numérique la plus proche dans la base de données

Voici mon instruction select jusqu'à présent.

SELECT * FROM [myTable] 
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' 
ORDER BY Area DESC 

Ce que je dois faire est de trouver la plus proche du champ « Zone », donc si mon entrée est de 1,125 et la base de données contient 2, 1,5, 1 et 0,5 la requête renvoie le dossier contenant 1 Mes compétences SQL sont très limitées donc toute aide serait appréciée.

Répondre

56

obtenir la différence entre la zone et votre entrée, prenez valeur absolue donc toujours positive, alors l'ordre croissant et prendre le premier

SELECT TOP 1 * FROM [myTable] 
WHERE Name = 'Test' and Size = 2 and PType = 'p' 
ORDER BY ABS(Area - @input) 
2

Que diriez-vous de commander la différence entre votre entrée et [Zone], tels que:

DECLARE @InputValue DECIMAL(7, 3) 

SET @InputValue = 1.125 

SELECT TOP 1 * FROM [myTable] 
WHERE Name = 'Test' AND Size = 2 AND PType = 'p' 
ORDER BY ABS(@InputValue - Area) 
0

Si vous utilisez MySQL

SELECT * FROM [myTable] ... ORDER BY ABS(Area - SuppliedValue) LIMIT 1 
7

quelque chose d'horrible, de la manière suivante:

ORDER BY ABS(Area - 1.125) ASC LIMIT 1 

Peut-être?

2
SELECT * 
    FROM [myTable] 
    WHERE Name = 'Test' AND Size = 2 AND PType = 'p' 
    ORDER BY ABS(Area - 1.125) 
    LIMIT 1 

- MarkusQ

1

Notez que bien que ABS() est supporté par à peu près tout, ce n'est pas techniquement standard (dans SQL99 au moins). Si vous devez écrire SQL standard ANSI pour une raison quelconque, vous auriez à contourner le problème avec un opérateur CASE:

SELECT * FROM myTable 
WHERE Name='Test' AND Size=2 AND PType='p' 
ORDER BY CASE Area>1.125 WHEN 1 THEN Area-1.125 ELSE 1.125-Area END 
2

Si vous avez plusieurs lignes qui répondent à l'égalité des prédicats sur Name, Size et PType colonnes Vous pouvez ensuite inclure des prédicats de plage dans la colonne Area de votre requête. Si la colonne Area est indexée, cela peut permettre un accès basé sur un index efficace.

La requête suivante (écrit en utilisant la syntaxe Oracle) utilise une branche d'un UNION ALL pour trouver l'enregistrement avec un minimum Area >= votre cible, tandis que l'autre branche trouve le record avec maximal Area < votre cible. L'un de ces deux enregistrements sera l'enregistrement que vous recherchez. Ensuite, vous pouvez ORDER BY ABS(Area - ?input) pour choisir le gagnant parmi ces deux candidats. Malheureusement, la requête est complexe en raison des SELECTS imbriqués qui sont nécessaires pour appliquer la priorité ROWNUM/ORDER BY souhaitée.

SELECT * 
FROM 
    (SELECT * FROM 
    (SELECT * FROM 
     (SELECT * FROM [myTable] 
     WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area >= ?target 
     ORDER BY Area) 
     WHERE ROWNUM < 2 
    UNION ALL 
    SELECT * FROM 
     (SELECT * FROM [myTable] 
     WHERE Name = 'Test' AND Size = 2 AND PType = 'p' AND Area < ?target 
     ORDER BY Area DESC) 
     WHERE ROWNUM < 2) 
    ORDER BY ABS(Area - ?target)) 
WHERE rownum < 2 

Un bon indice pour cette requête serait (Name, Size, PType, Area), auquel cas le plan d'exécution de la requête attendue serait basée sur deux scans de plage d'index que chaque ligne unique a renvoyé une.

-2

Sélectionnez le min où [champ]> your_target_value Sélectionnez le max où [champ] < your_target_value

+1

Bienvenue sur SO et merci pour essayer de contribuer! Mais il y a des choses à améliorer dans votre réponse pour être utile.Premièrement, le balisage est cassé. Les blocs de code doivent être indentés de 4 espaces, voir [edit help] (http://stackoverflow.com/editing-help). En dehors de cela, une explication serait utile car les réponses au code seulement sont généralement difficiles à comprendre. Affirmer que votre réponse est un pseudocode SQL ou la réécrire en SQL normal serait bien aussi. Pourtant, votre réponse est utile et après avoir édité les problèmes, il peut être upvoted. – Palec

Questions connexes