Order by: Special characters before ABC - oracle

I have this sql:
SELECT -1 AS ID, '(None)' AS NAME
FROM TABLE_1 WHERE ID=1
UNION
SELECT ID, NAME
FROM TABLE_2
ORDER BY 2
Table data:
ID | NAME
1 | Direct
2 | Personal
3 | Etc
So if i execute this sql in Oracle 10 it returns these:
Result:
ID | NAME
1 | Direct
3 | Etc
-1 | (None)
2 | Personal
How is it possible to sort the "(None)" always to the top?
If i use
' (None) ' as Name
instead of
'(None)' as Name
It works, because the space before the (None), but that is not a solution.

You can add a dummy column ORDER_COL and then order on that column
select ID, NAME from
(
SELECT -1 AS ID, '(None)' AS NAME, 1 as ORDER_COL FROM TABLE_1 WHERE ID=1
UNION
SELECT ID, NAME, 2 as ORDER_COL FROM TABLE_2
)
order by ORDER_COL, NAME;

Try this. NULLS LAST is the default for ascending order in Oracle. make it NULLS FIRST for '(None)'. Also, use UNION ALL as UNION removes duplicates and is less efficient.
SELECT *
FROM (
SELECT -1 AS ID
,'(None)' AS NAME
FROM TABLE_1
WHERE ID = 1
UNION ALL
SELECT ID
,NAME
FROM TABLE_2
)
ORDER BY CASE
WHEN NAME = '(None)'
THEN NULL
ELSE NAME -- or id if you want
END NULLS FIRST;

Related

Reverse of ascii function in Oracle

When I do following query
select asciistr(first_name) from person where id = 1
the result contains '\200D'.
So what is the reverse function of converting a '\200D' to character, so I can find all names with that specific character.
You want UNISTR (and, maybe, CAST it to a VARCHAR2). If you have the table:
CREATE TABLE person ( first_name, id ) AS
SELECT 'A', 1 FROM DUAL UNION ALL
SELECT CAST( UNISTR( '\200D' ) AS VARCHAR2(20) ), 1 FROM DUAL;
Then the output from your query:
select first_name,
asciistr(first_name)
from person
where id = 1
Is:
FIRST_NAME | ASCIISTR(FIRST_NAME)
:--------- | :-------------------
A | A
? | \200D
db<>fiddle here
\200D is the U+200D ZERO WIDTH JOINER
If you like to find names with this (non printable) character try
SELECT *
FROM person
WHERE first_name LIKE '%'||UNISTR('\200D')||'%'
or
WHERE asciistr(first_name) LIKE '%\200D%'

rewrite query without DENSE_RANK

I have one very slow query and try to optimize response time by using a materialized view. But one part is not compatible with General Restrictions on Fast Refresh.
How to rewrite it without DENSE_RANK?
create table t (id,object_id,log_cre_date) as
select 1,2,to_date('18/5/2010, 08:00','dd/mm/yyyy, hh:mi') from dual union all
select 2,2,to_date('18/5/2010, 10:00','dd/mm/yyyy, hh mi') from dual union all
select 3,3,to_date('18/5/2010, 11:00','dd/mm/yyyy, hh mi') from dual union all
select 4,3,to_date('18/5/2010, 12:10','dd/mm/yyyy, hh mi') from dual union all
select 5,4,to_date('18/5/2010, 12:20','dd/mm/yyyy, hh mi') from dual union all
select 6,4,to_date('18/5/2010, 11:30','dd/mm/yyyy, hh mi') from dual;
SELECT
MAX(t.id) KEEP(DENSE_RANK FIRST ORDER BY log_cre_date ASC) id,
t.object_id
FROM
t
GROUP BY
t.object_id
I am not sure the accepted answer is fast refreshable. Here is a query that definitely is:
SELECT max(cast(to_char(t.log_cre_date,'YYYYMMDDHH24MISS') || lpad(t.id,30,'0') as varchar2(80))) maxid,
t.object_id,
COUNT(*) cnt
FROM t
GROUP BY t.object_id;
The idea is to append the id to the log_cre_date and take the max of the concatenation. That way, you can extract the id you need later.
So, to get the id, you would do this:
SELECT to_char(substr(maxid,-30)) id, object_id
FROM your_materialized_view;
You could put that in a view to hide the complexity.
Here is a full example:
Create the base table
DROP TABLE t;
create table t (id,object_id,log_cre_date) as
select 1,2,to_date('18/5/2010, 08:00','dd/mm/yyyy, hh:mi') from dual union all
select 2,2,to_date('18/5/2010, 10:00','dd/mm/yyyy, hh mi') from dual union all
select 3,3,to_date('18/5/2010, 11:00','dd/mm/yyyy, hh mi') from dual union all
select 4,3,to_date('18/5/2010, 12:10','dd/mm/yyyy, hh mi') from dual union all
select 5,4,to_date('18/5/2010, 12:20','dd/mm/yyyy, hh mi') from dual union all
select 6,4,to_date('18/5/2010, 11:30','dd/mm/yyyy, hh mi') from dual;
Add some constraints to allow fast-refresh MV
ALTER TABLE t MODIFY id NOT NULL;
ALTER TABLE t ADD CONSTRAINT t_pk PRIMARY KEY ( id );
Create a snapshot log to enable fast refresh
--DROP MATERIALIZED VIEW LOG ON t;
CREATE MATERIALIZED VIEW LOG ON t WITH ROWID, PRIMARY KEY (OBJECT_ID, LOG_CRE_DATE) INCLUDING NEW VALUES;
Create the materialized view (note presence of COUNT(*) in select-list. Important!
--DROP MATERIALIZED VIEW t_mv;
CREATE MATERIALIZED VIEW t_mv
REFRESH FAST ON COMMIT AS
SELECT max(cast(to_char(t.log_cre_date,'YYYYMMDDHH24MISS') || lpad(t.id,30,'0') as varchar2(80))) maxid,
t.object_id,
COUNT(*) cnt
FROM t
GROUP BY t.object_id;
Test it out
select to_number(substr(maxid,-30)) id, object_id
from t_mv;
+----+-----------+
| ID | OBJECT_ID |
+----+-----------+
| 2 | 2 |
| 4 | 3 |
| 5 | 4 |
+----+-----------+
DELETE FROM t WHERE id = 5;
COMMIT;
select to_number(substr(maxid,-30)) id, object_id
from t_mv;
+----+-----------+
| ID | OBJECT_ID |
+----+-----------+
| 4 | 3 |
| 5 | 4 |
| 1 | 2 | -- Now ID #1 is the latest for object_id 2
+----+-----------+
Maybe this query will run faster:
select object_id, id
from (
select object_id, first_value(id) over(partition by object_id order by log_cre_date) as id
from t
)
group by object_id, id;
Hope it helps!
I went through the restriction but I am not sure if following query will work or not.
Try this and let us know if it works.
Select t.id, t.object_id from
T join
(SELECT
min(log_cre_date) mindt,
t.object_id
FROM
t
GROUP BY
t.object_id) t1
On t.object_id = t1.object_id
And t.log_cre_date = t1.mindt;
Cheers!!

display multiple column records in one column in oracle

I have Table having following columns in Oracle;
ID NIC NTN MBL NAME
---------------------------------------
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 624
I need to display like this in select query
ID NIC/NTN/MBL NAME
1 1234512 ABC
2 321 XYZ
3 5421 POI
4 541245 // taking first value
I was trying to do with
SELECT
A.ID,
"CNIC/NTN/MBL"
A.NAME,
A.REASON
B.NAME
FROM TABLEA A
INNER JOIN TABLEB B ON A.R_ID = B.R_ID
UNPIVOT INCLUDE NULLS
(
CNIC/NTN/MBL FOR cols IN (A.NIC, A.NTN, A.MBL)
)
but unable to do.
Use COALESCE:
SELECT
ID,
COALESCE(NIC, NTN, MBL) AS "NIC/NTN/MBL",
NAME
FROM yourTable;
This should work because in the call to COALESCE above, I list the three columns from left to right, and the first non NULL value will be retained.
You need the COALESCE function (which simply returns the first non-null value in the specified inputs, reading from left to right), like so:
WITH your_table AS (SELECT 1 ID, 1234512 nic, NULL ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 2 ID, NULL nic, 321 ntn, NULL mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 3 ID, NULL nic, NULL ntn, 5421 mbl, 'ABC' NAME FROM dual UNION ALL
SELECT 4 ID, 541245 nic, 624 ntn, NULL mbl, 'ABC' NAME FROM dual)
SELECT ID,
COALESCE(nic, ntn, mbl) nic_ntn_mbl,
NAME
FROM your_table;
ID NIC_NTN_MBL NAME
---------- ----------- ----
1 1234512 ABC
2 321 ABC
3 5421 ABC
4 541245 ABC

Counting null dates in Oracle

I have a question with null dates in Oracle
I've got a table like this:
ID DATE
1 '02/08/2015'
1 NULL
1 '02/06/2014'
2 NULL
2 '06/02/2013'
This is just an example of the real table. Now what I need is something like this:
ID DAY_INAC
1 1
2 1
I mean, I need to count only the null values present in the DATE column.
But when I execute my query
Select id, count(date)
from table
where date is null
group by Id
having count(date)>0
As a result I'm getting nothing. What do I need to with the date value in order to generate the corresponding counting.
Regards
Because your query is already filtering by date is null, you just need to use count(*)
Select id, count(*)
from table
where date is null
group by Id
having count(*) > 0
COUNT does not count NULL values. You can use CASE to change them:
Select id, count(CASE WHEN date IS NULL THEN 1 END) AS DAY_INAC
from table
where date is null
group by Id;
LiveDemo
Please do not name column as datatypes. Otherwise you may need to quote them.
A more condensed query:
Select id, count(nvl2(date_column,null, sysdate)) as cnt
from table
group by Id;
COUNT will not count NULL values - instead get it to count a literal value (i.e. 1) for those rows that are NULL:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE table_name ( ID, "DATE" ) AS
SELECT 1, DATE '2015-08-02' FROM DUAL
UNION ALL SELECT 1, NULL FROM DUAL
UNION ALL SELECT 1, DATE '2014-06-02' FROM DUAL
UNION ALL SELECT 2, NULL FROM DUAL
UNION ALL SELECT 2, DATE '2013-02-06' FROM DUAL
Query 1:
SELECT id,
COUNT(1)
FROM table_name
WHERE "DATE" IS NULL
GROUP BY id
Results:
| ID | COUNT(1) |
|----|----------|
| 1 | 1 |
| 2 | 1 |

select rows having same column value

I am trying to form a query for following scenario
if my table is
signature | id | operation
abc | 1 | 1234
xyz | 1 | 1234
pqr | 2 | 1234
then my output should be
signature | id
abc | 1
xyz | 1
i.e. rows having same value in a particular column.
i have formed query like
select signature,id
from tablename
where operation = '1234'
group by signature,id
having count(*) >0;
but this is returning everything including xyz | 1 also.
Can someone suggest me correct query?
Try this:
SELECT signature,COUNT(id) FROM table_name WHERE operation = '1234' GROUP BY id;
I haven't tested this and it might be overly complicated but I THINK this will work:
SELECT Signature, ID from tablename WHERE ID in( SELECT ID FROM (SELECT ID, COUNT(*) as NumRecords from tablename GROUP BY ID HAVING NumRecords > 1)))
Try this:
We need to apply PARTITION on ID column as follows,
SELECT Result.[signature], Result.ID ,
ROW_NUMBER() over(PARTITION BY Result.ID ORDER BY Result.ID) AS [RowNum]
INTO #TempResult
FROM table_name AS Result
GROUP BY Result.[signature], Result.ID
SELECT Result.[signature], Result.ID
FROM #TempResult AS Result
where Result.[RowNum] = 1
You can use where exists for an alternative to group by
select
signature,
id
from tablename t1
where exists (
select * from tablename t2
where t1.id = t2.id
and t1.signature != t2.signature
and t1.operation = 1234
);

Resources