1

I have following schema

CREATE TABLE BookImage (Id UNSIGNED BIG INT, ImageId UNSIGNED BIG INT, IsDefault INT, 
                           PRIMARY KEY(Id, ImageId));

INSERT OR IGNORE INTO BookImage(Id,ImageId,IsDefault) VALUES (1,10,0);
INSERT OR IGNORE INTO BookImage(Id,ImageId,IsDefault) VALUES (1,11,1);
INSERT OR IGNORE INTO BookImage(Id,ImageId,IsDefault) VALUES (1,12,0);

INSERT OR IGNORE INTO BookImage(Id,ImageId,IsDefault) VALUES (2,20,0);
INSERT OR IGNORE INTO BookImage(Id,ImageId,IsDefault) VALUES (2,21,0);
INSERT OR IGNORE INTO BookImage(Id,ImageId,IsDefault) VALUES (2,22,0);

My target is to get a SELECT query to find (ImageId, Id) for given "Id" such that-

  1. if IsDefault=1, then return the row
  2. if IsDefault=0, then return the row of lowest ImageId

For given table, if I query with Id=1, it should return only (11,1) if I query with Id=2, it should return only (20,2) because there is not IsDefault=1 for Id=2.

I need a sqlite select query to achieve that. I have tried the query from this post but it is not working

SELECT * 
FROM BookImage 
WHERE Id=1 AND IsDefault=1
UNION ALL
SELECT * 
FROM BookImage 
WHERE Id=1 ORDER BY ImageId ASC LIMIT 1 AND NOT EXISTS (
    SELECT *
    FROM BookImage 
    WHERE Id=1 AND IsDefault=1 LIMIT 1 
)

http://sqlfiddle.com/#!5/e094e/1/0

1 Answers1

1

With ROW_NUMBER() window function:

SELECT Id, ImageId
FROM (
  SELECT *,
    ROW_NUMBER() OVER (PARTITION BY Id ORDER BY IsDefault DESC, ImageId) rn
  FROM BookImage
) b
WHERE rn = 1 AND Id = ?

Replace ? with the Id that you search for.
See the demo.

Another way:

SELECT Id, ImageId
FROM BookImage
WHERE Id = ?
ORDER BY ROW_NUMBER() OVER (ORDER BY IsDefault DESC, ImageId)
LIMIT 1

See the demo.

For older versions of SQLite that do not support window functions:

SELECT Id, ImageId 
FROM BookImage
WHERE Id = ?
ORDER BY IsDefault DESC, ImageId
LIMIT 1;

See the demo.
Results for Id = 1:

| Id  | ImageId |
| --- | ------- |
| 1   | 11      |

Results for Id = 2:

| Id  | ImageId |
| --- | ------- |
| 2   | 20      |
forpas
  • 160,666
  • 10
  • 38
  • 76
  • Thanks for your help. But it is not the exact thing I am looking for. If I search with Id=1, it should retrun (11,1) only. If I query with id=2 then it should return only (20,2). – John Cooper May 07 '20 at 16:53
  • Check my edited answer. Replace ? with the id that you search for. – forpas May 07 '20 at 17:02
  • Yes this exactly I am looking for. But your statement is failing here: http://sqlfiddle.com/#!7/e094e Could you have a look? – John Cooper May 07 '20 at 17:09
  • @JohnCooper check another simpler way. – forpas May 07 '20 at 17:11
  • I guess that the fiddle in your link uses an older version of SQLite that does not support window functions. – forpas May 07 '20 at 17:15
  • Yes, I guess so, I am checking whether my system's version supports window functions or not :( – John Cooper May 07 '20 at 17:18
  • No this is not the case. It uses SQLite 3.31.1. I just checked. So I don't know why it fails. All the queries work fine in any other environment – forpas May 07 '20 at 17:20
  • If you want to use it in Android it will not work. Android as far as I know uses an older version. I will post another query. – forpas May 07 '20 at 17:25
  • No I don't use it with Android, I checked with my system's, window functions are failing there also. (SQLite 3.7.17 2013-05-20) – John Cooper May 07 '20 at 17:31
  • I think that the last query is the simplest. – forpas May 07 '20 at 17:58
  • Yes!! your last 2 queries worked with the SQLite version (3.7.17) I am working working with. Definitely this is an expert answer, can't vote you more :D – John Cooper May 07 '20 at 17:59
  • I removed these queries because I posted a simpler query. Check it. – forpas May 07 '20 at 18:00