Perhaps consider an alternative approach that does not need the CASE THEN ELSE assuming that the cardduedatetime adheres to the specified datetime formats as per SQLite date time formats (according to you output the dates do appear to at least be sortable and therefore are close to such dates)
e.g. :-
SELECT *
FROM cards_table
ORDER BY
/* coalesce so null date (invalid datetime returns null)*/
/* if null then use the maxdatetime less the cardid */
coalesce(strftime('%s',cardduedatetime),strftime('%s','3000-12-31 23:59') /*number larger tha*/)-cardid ASC;
- comments added to explain
- the
coalesce function is basically an if-then construct used to provide a sortable value in either case.
Using the following to demonstrate:-
/* just in case cleanup*/
DROP TABLE IF EXISTS cards_table;
/* create the table*/
CREATE TABLE IF NOT EXISTS cards_table (cardid INTEGER PRIMARY KEY, cardtype TEXT, cardduedatetime TEXT, cardtitle TEXT);
/* populate the table as per the question */
INSERT INTO cards_table VALUES
(1,'Buy', NULL,'TEST 1')
,(2,'Buy',NULL,'TEST 2')
,(3,'Buy','2025-09-24 23:59','TEST 3')
,(4,'Buy','2025-09-26 23:59','TEST 4')
;
SELECT *,
/* for demonstration show the derived sortable value */
coalesce(strftime('%s',cardduedatetime),strftime('%s','3000-12-31 23:59') /*number larger tha*/)-cardid AS showval
FROM cards_table
ORDER BY
/* coalesce so null date (invalid datetime returns null)*/
/* if null then use the maxdatetime less the cardid (which will be greater than an actual date)*/
coalesce(strftime('%s',cardduedatetime),strftime('%s','3000-12-31 23:59') /*number larger tha*/)-cardid ASC;
/* cleanup after enviroment after the test */
DROP TABLE IF EXISTS cards_table;
Then the output is:-

The showval column included to demonstrate the value that is sorted i.e. IF valid datetime THEN that datetime ELSE the date 12/31/3000 (US format) in either case less the card id thus for invalid dates the latest cardid will appear higher in the list.
- likewise valid datetimes that are the same
- instead of
strftime('%s','3000-12-31 23:59') a hard coded high value could be used such as 9999999999. However, the former is perhaps clearer to understand.
- note the showval column for the last two and how the cardid is subtracted to show the latest (higher cardid) higher in the output.
Note shown/indicated as an issue if a row with the same datetime appears such as one inserted using ,(5,'Buy','2025-09-26 23:59','TEST 5') /*demonstrate same duedatetime*/ then that would appear before TEST 4 e.g. :-
