问题
The context here is a SQLCipher database in an Android app. The context here is a SQLCipher database in an Android app. The context here is a SQLCipher database in an Android app. Consider the following SQLite table
CREATE TABLE IF NOT EXISTS test(a INTEGER NOT NULL,b INTEGER NOT NULL,c INTEGER NOT NULL,d INTEGER NOT NULL);
into which I insert the following rows
INSERT INTO test (a,b,c,d) VALUES(1,2,3,4);
INSERT INTO test (a,b,c,d) VALUES(1,2,3,5);
INSERT INTO test (a,b,c,d) VALUES(1,2,5,5);
INSERT INTO test (a,b,c,d) VALUES(1,5,5,5);
INSERT INTO test (a,b,c,d) VALUES(5,5,5,5);
A simple SELECT COUNT(*) FROM test WHERE a = 1 OR b = 2 or c = 3 or d = 4;
would return 4
as the result since 4 of the 5 rows have one or more matching values. What I need to do is to find the "best" match, i.e. the one that satisfies the most WHERE .. OR
conditions. In the present instance this would return the first row where all four columns match. While I could simply get a cursor back on a raw select along the lines of SELECT * FROM test WHERE a = 1 OR b = 2 or c = 3 or d = 4;
and then do the rest in Java I am wondering if there isn't a way to do this directly within SQLite itself.
回答1:
Use the expression:
(a=1) + (b=2) + (c=3) + (d=4)
in the ORDER BY
clause:
SELECT *
FROM test
ORDER BY (a=1) + (b=2) + (c=3) + (d=4) DESC
LIMIT 1
Each of the terms: (a=1)
, (b=2)
, (c=3)
and (d=4)
evaluates to 1
for TRUE
or 0
for FALSE
.
See the demo.
If you want ties in the results use a CTE:
WITH cte AS (
SELECT *, (a=1) + (b=2) + (c=3) + (d=4) counter
FROM test
)
SELECT a, b, c, d
FROM cte
WHERE counter = (SELECT MAX(counter) FROM cte)
See the demo.
Or with RANK()
window function:
WITH cte AS (
SELECT *, RANK() OVER (ORDER BY (a=1) + (b=2) + (c=3) + (d=4) DESC) rn
FROM test
)
SELECT a, b, c, d
FROM cte
WHERE rn = 1
See the demo.
Results:
| a | b | c | d |
| --- | --- | --- | --- |
| 1 | 2 | 3 | 4 |
来源:https://stackoverflow.com/questions/60538227/sqlite-select-ordering-by-best-match