I want conditionally orderBy my query. All completed tasks (completed 1) should be below uncompleted and ordered by completion time and uncompleted task should be ordered by priority value. I am getting this with following statement:
orderBy = TaskTable.COLUMN_TASK_COMPLETED + " ASC, CASE " +TaskTable.COLUMN_TASK_COMPLETED+" WHEN 0 THEN " +TaskTable.COLUMN_TASK_PRIORITY +" WHEN 1 THEN "+TaskTable.COLUMN_TASK_COMPLETED_TIME + " END DESC";
Now, I want to change it, such way that priority is ordered with ASC attribute and completed_time is ordered with DESC attribute.
I tried:
orderBy = TaskTable.COLUMN_TASK_COMPLETED + " ASC, CASE " +TaskTable.COLUMN_TASK_COMPLETED+" WHEN 0 THEN " +TaskTable.COLUMN_TASK_PRIORITY +" ASK WHEN 1 THEN "+TaskTable.COLUMN_TASK_COMPLETED_TIME + " DESC END";
But it returns error:
Caused by: android.database.sqlite.SQLiteException: near "ASC": syntax error (code 1): , while compiling: SELECT * FROM task_table WHERE (task_name LIKE ? ) ORDER BY task_completed ASC, CASE task_completed WHEN 0 THEN task_priority ASC WHEN 1 THEN task_completed_time DESC END
How to fix it?
The ASC/DESC specifications can be applied only to the top-level expressions used in the ORDER BY clause.
When you have a numeric column, you can simply negate its values, i.e., sort not by X but by -X.
Related
I define Room Dao with Query like this:
#Query(
"SELECT " +
"COUNT(*) FILTER(WHERE f > 1) as count1 " +
"FROM myTable WHERE ..."
)
and get an error:
extraneous input '(' expecting {<EOF>, ';', K_ALTER, K_ANALYZE, K_ATTACH, K_BEGIN, K_COMMIT, K_CREATE, K_DELETE, K_DETACH, K_DROP, K_END, K_EXPLAIN, K_INSERT, K_PRAGMA, K_REINDEX, K_RELEASE, K_REPLACE, K_ROLLBACK, K_SAVEPOINT, K_SELECT, K_UPDATE, K_VACUUM, K_VALUES, K_WITH, UNEXPECTED_CHAR}
I suppose the compiler doesn't understand '(' after FILTER keyword.
I use kapt "androidx.room:room-compiler:2.4.1" in my build.gradle.
I have shown the simplified query, in the real one, I have more than one COUNT(*) fields and cannot move WHERE after FROM.
I used the aggregator syntax from https://www.sqlite.org/lang_aggfunc.html#count
The FILTER clause for aggregate functions is supported by SQLite since version 3.30.0 (2019-10-04).
This version of SQLite is used by Android only for API Level 31+ (which is currently the latest).
This means that if your code runs in a device with a lower API Level you will not be able to use this new feature.
An alternative would be conditional aggregation:
#Query(
"SELECT " +
"COUNT(CASE WHEN f > 1 THEN 1 END) AS count1 " +
"FROM myTable WHERE ..."
)
or with TOTAL() aggregate function:
#Query(
"SELECT " +
"TOTAL(f > 1) AS count1 " +
"FROM myTable WHERE ..."
)
I would like to utilize the Month Column in the below syntax in a Case Statement. When I create a sub query I receive the Oracle error 01788 Connect By Clause Required in query block. How can one utilize the Month column in the case statment in the subquery?
TO_CHAR(ADD_MONTHS(TRUNC(StartDate, 'MM'), LEVEL - 1), 'YYYYMM') AS Month
Query below:
SELECT
CASE
WHEN first_assgn_dt_YYYYMM <= Month
THEN 0
WHEN EndDate < LAST_DAY(EndDate) AND EndDate != sysdate
AND LEVEL = 1 + MONTHS_BETWEEN(TRUNC(EndDate,'MM'),TRUNC(StartDate,'MM'))
THEN 0
ELSE 1
END AS active_at_month_end
FROM (
WITH
ActiveMemberData (ID,StartDate,EndDate,first_assgn_dt,first_assgn_dt_YYYYMM) AS (
SELECT DISTINCT
x.ID,
TRUNC(x.start_dt) AS StartDate,
CASE WHEN TRUNC(X.END_DT) = '1-JAN-3000' THEN SYSDATE ELSE TO_DATE(X.END_DT) END AS EndDate,
x.first_assgn_dt,
TO_CHAR(first_assgn_dt,'YYYYMM') AS first_assgn_dt_YYYYMM
FROM X
LEFT JOIN D ON X.MID = D.ID
WHERE 1=1
)
--------------------------------------------------
SELECT DISTINCT
ID,
first_assgn_dt,
first_assgn_dt_YYYYMM,
StartDate,
TO_CHAR(StartDate,'YYYYMM') AS StartDate_YYYYMM,
EndDate,
TO_CHAR(ADD_MONTHS(TRUNC(StartDate, 'MM'), LEVEL - 1), 'YYYYMM') AS Month,
LAST_DAY(EndDate) AS LastDayOfMonth
FROM ActiveMemberData
WHERE 1=1
------------------------------------------------------------------------------------
CONNECT BY LEVEL <= 1 + MONTHS_BETWEEN(TRUNC(EndDate,'MM'), TRUNC(StartDate,'MM'))
AND PRIOR ID = ID AND PRIOR STARTDATE = STARTDATE
AND PRIOR sys_guid() IS NOT NULL
) Z
WHERE 1=1
ORDER BY
ID,
Month
That has nothing to do with trying to refer to Month from the inline view; that is fine. It's the separate reference to level that is causing the error.
If you want to be able to see the level from your inline view in the outer query, as you are with this line:
AND LEVEL = 1 + MONTHS_BETWEEN(TRUNC(EndDate,'MM'),TRUNC(StartDate,'MM'))
then you have to include it in the select list - with an alias - and then refer to that alias:
SELECT
CASE
...
AND LEVEL_ALIAS = 1 + MONTHS_BETWEEN(TRUNC(EndDate,'MM'),TRUNC(StartDate,'MM'))
...
FROM (
...
SELECT DISTINCT
LEVEL as LEVEL_ALIAS,
ID,
...
You can call the alias whatever you want, of course; you just can't use the reserved word level.
Anything you want visible in the outer query always has to be in the inline view's select list - but usually you can keep the original column name; you have to use an alias for an expression or a pseucocolumn though, which is the case here.
You don't have to use an alias for the reserved word. Just add double quotes and capitilise it i.e. "LEVEL"
I have a table ContactsCategoriesTable with a column name. Names in such column can be anything and 'UNSORTED' in particular. I want to make such an order by clause that my query is first sorted by ContactsCategoriesTable.Name, then by ContactsTable.NAME and UNSORTED rows are always at the bottom of table.
I tried this code, but without success. How to write such a clause?
sortOrder = ContactsCategoriesTable.NAME + " ASC, " + ContactsTable.NAME + " ASC, "
+ ContactsCategoriesTable.NAME + " = 'UNSORTED' ASC ";
A category name being "UNSORTED" is 'stronger' than any other sorting criteria, so you need to sort by that first:
ORDER BY Category.Name = 'UNSORTED', Category.Name, Contact.Name
I have:
PROCEDURE A
(
inId IN NUMBER,
RC1 OUT SYS_REFCURSOR
) IS
tMessage VARCHAR2(128);
BEGIN
OPEN RC1 FOR
SELECT * FROM
(
SELECT
a.company,
SUM(a.holding_balance) balance
FROM TableNameEntries A
WHERE
A.BATCH_ID = inId
GROUP BY a.company
)
ORDER BY balance DESC ;
EXCEPTION
WHEN OTHERS THEN
tMessage :='Exception ' || SQLCODE || ': ' || SQLERRM;
OPEN RC1 FOR
SELECT tMessage FROM DUAL;
END A;
For the balance column, I have values like -1, 0,1. Currently it's sorted like 1 0 -1, but I don't care about the zeros, so I want it to be like -1,1,0 or 1,-1,0
How do I do it in PL/SQL? I tried:
SELECT
a.company,
SUM(a.holding_balance) balance
FROM REC.CAG_GL_ENTRIES A
WHERE
A.BATCH_ID = 201311
order by case priority when 0 then 2 else 1 END priority
But it's saying PRIORITY is invalid identifier.
How can I get this to work?
Try:
ORDER BY CASE balance
WHEN 0 THEN null
ELSE balance
END
DESC NULLS LAST
there are two ways in your case (second is more common, first is more clear):
SELECT a.company,
SUM(a.holding_balance) balance
FROM REC.CAG_GL_ENTRIES A
WHERE A.BATCH_ID = 201311
order by abs(balance) desc;
SELECT a.company,
SUM(a.holding_balance) balance
FROM REC.CAG_GL_ENTRIES A
WHERE A.BATCH_ID = 201311
order by decode(balance,1,1,-1,1,2);
ORDER BY SIGN(ABS(balance)) DESC, balance
ABS() turns all the negatives to positives. SIGN() turns 0 to 0, >0 to 1 (and <0 to -1). Combined with DESC this puts all the zeros at the end and all the non-zeros above them in no particular order.
Then I sorted by the balance again to order the non-zeros.
You can also use
order by balance * balance desc
I am generating an SQL query:
SELECT * FROM ToDoList
WHERE ws_status <> 'Completed'
AND (user_id= 'TESTUSR' OR ww_cover='TESTUSR'
OR (ws_status = 'Orphan' AND wwt_workgroupid IN (108)))
**ORDER BY psc_alt_code ASC**
And I need to list all results with wi_urgent set to 'Y' and order them by date Desc *first and then list all other results ordered by psc_alt_code descending* so I thought something like this would suffice:
ORDER BY (wi_urgent = 'Y') DESC, psc_alt_code ASC
I am getting SqlClient.SqlException: Incorrect syntax near '=' error when trying to run that query. Please note that I am querying an SQL View if that makes a difference?
You can use a case expression in the order by
SELECT * FROM ToDoList
WHERE ws_status <> 'Completed'
AND (user_id= 'TESTUSR' OR ww_cover='TESTUSR'
OR (ws_status = 'Orphan' AND wwt_workgroupid IN (108)))
ORDER BY CASE WHEN wi_urgent = 'Y' THEN 0 ELSE 1 END ASC
,psc_alt_code
I don't think you can do wi_urgent = 'Y' in an ORDER BY.
Since you're looking for all results with wi_urgent, try adding it to the WHERE clause:
SELECT * FROM ToDoList
WHERE ws_status <> 'Completed'
AND (user_id= 'TESTUSR' OR ww_cover='TESTUSR'
OR (ws_status = 'Orphan' AND wwt_workgroupid IN (108)))
AND wi_urgent = 'Y'
ORDER BY wi_urgent DESC,
psc_alt_code ASC