2009-02-26 18 views
33

Devo trovare un'istruzione select che restituisca esattamente un record che corrisponda esattamente al mio input o la corrispondenza più vicina se non viene trovata una corrispondenza esatta.Trova il valore numerico più vicino nel database

Ecco la mia dichiarazione selezionata finora.

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

Che cosa devo fare è trovare la corrispondenza più vicina al campo 'Area', quindi se il mio ingresso è 1,125 e il database contiene 2, 1.5, 1 e 0,5 la query restituirà il record contenente 1

Le mie competenze SQL sono molto limitate quindi qualsiasi aiuto sarebbe apprezzato.

risposta

56

ottenere la differenza tra la superficie e il vostro ingresso, prende valore assoluto in modo sempre positivo, quindi ordine crescente e prendere il primo

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

Come su come ordinare dalla differenza tra l'input e [Area], come ad esempio:

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

Se si utilizza MySQL

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

qualcosa di orribile, lungo le linee di:

ORDER BY ABS(Area - 1.125) ASC LIMIT 1 

Forse?

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

- MarkusQ

1

Nota che, anche se ABS() è supportato da praticamente tutto, non è tecnicamente standard (nell'SQL99 almeno). Se si deve scrivere ANSI SQL standard per qualche ragione, che avrebbe dovuto risolvere il problema con un operatore CASO:

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

Se si dispone di molte righe che soddisfano l'uguaglianza predicati sul Name, Size e PType colonne quindi potresti voler includere i predicati di intervallo sulla colonna Area nella tua query. Se la colonna Area è indicizzata, ciò potrebbe consentire un accesso efficiente basato su indice.

la seguente query (scritto utilizzando la sintassi Oracle) utilizza un ramo di un UNION ALL per trovare il record con il minimo Area >= vostro obiettivo, mentre l'altro ramo trova il record con la massima Area < il vostro target. Uno di questi due record sarà il record che stai cercando. Quindi puoi ORDER BY ABS(Area - ?input) scegliere il vincitore tra quei due candidati. Sfortunatamente la query è complessa a causa di SELEZIONI nidificati che sono necessari per far rispettare la priorità desiderata di ROWNUM/ORDER BY.

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 buon indice per questa ricerca sarebbe (Name, Size, PType, Area), nel qual caso il piano di esecuzione di query previsto sarebbe basato su due scansioni gamma indice che ogni restituiti una singola riga.

-2

Selezionare il min dove [campo]> your_target_value Selezionare il massimo in cui [campo] < your_target_value

+1

Benvenuti a SO e grazie per aver cercato di contribuire! Ma ci sono alcune cose da migliorare nella tua risposta per essere utile.Innanzitutto, il markup è rotto. I blocchi di codice dovrebbero essere indentati di 4 spazi, vedere [aiuto per la modifica] (http://stackoverflow.com/editing-help). Oltre a questo, una spiegazione sarebbe utile in quanto le risposte solo in codice sono generalmente difficili da comprendere. Dire che la tua risposta è pseudocodice SQL o riscriverla a SQL regolare sarebbe anche bello. Tuttavia, la tua risposta è utile e dopo aver eliminato i problemi, potrebbe essere svitato. – Palec

Problemi correlati