DISTINCT date value in ORA-01791: not a SELECTed expression - sql

I would like to get the unique date values from order table using oracle query. I am getting
ORA-01791: not a SELECTed expression
error, When i tried this below query
SELECT DISTINCT (TO_DATE(LAST_INSERT_TIMESTAMP, 'YYYY-MM-DD HH24:MI'))
FROM ORDER
WHERE LAST_INSERT_TIMESTAMP IS NOT NULL
ORDER BY LAST_INSERT_TIMESTAMP DESC;

LAST_INSERT_TIMESTAMP is not in your result list, because you have aggregated your rows with DISTINCT to a truncated timestamp. You can only order by this.
SELECT DISTINCT TRUNC(LAST_INSERT_TIMESTAMP, 'MI')
FROM ORDER
WHERE LAST_INSERT_TIMESTAMP IS NOT NULL
ORDER BY TRUNC(LAST_INSERT_TIMESTAMP, 'MI') DESC;
If you don't want to repeat the expression use positional sort:
ORDER BY 1 DESC;
Or use an alias for the expression:
SELECT DISTINCT TRUNC(LAST_INSERT_TIMESTAMP, 'MI') AS LAST_INSERT
FROM ORDER
WHERE LAST_INSERT_TIMESTAMP IS NOT NULL
ORDER BY LAST_INSERT DESC;
Please note that I replaced your TO_DATE with the appropriate TRUNC because all you want to do is truncate your timestamp, not convert to and from string.

Related

Oracle SQL group by to_char - not a group by expression

I want to group by dd-mm-yyyy format to show working_hours per employee (person) per day, but I get error message ORA-00979: not a GROUP BY expression, when I remove TO_CHAR from GROUP BY it works fine, but that's not I want as I want to group by days regardless hours, what am I doing wrong here?
SELECT papf.person_number emp_id,
to_char(sh21.start_time,'dd/mm/yyyy') start_time,
to_char(sh21.stop_time,'dd/mm/yyyy') stop_time,
SUM(sh21.measure) working_hours
FROM per_all_people_f papf,
hwm_tm_rec sh21
WHERE ...
GROUP BY
papf.person_number,
to_char(sh21.start_time,'dd/mm/yyyy'),
to_char(sh21.stop_time,'dd/mm/yyyy')
ORDER BY sh21.start_time
ORDER BY sh21.start_time
needs to either be just the column alias defined in the SELECT clause:
ORDER BY start_time
or use the expression in the GROUP BY clause:
ORDER BY to_char(sh21.start_time,'dd/mm/yyyy')
If you use sh21.start_time then the table_alias.column_name syntax refers to the underlying column from the table and you are not selecting/grouping by that.

Sort the date when using group by, where the display format of the date is user defined

In the below query,
SELECT TO_CHAR(hiredate,'MON-YYYY') Year_of_Hiring, COUNT(empno) No_of_Joinees
FROM emp
GROUP BY TO_CHAR(hiredate,'MON-YYYY');
How should I mention the format in ORDER BY clause, if I want to sort the result by hiredate.
You can use an aggregation function to order by the original date:
order by min(hiredate)
You can group by and order by TRUNC(hiredate, 'MM') and then format it in the SELECT clause:
SELECT TO_CHAR(TRUNC(hiredate, 'MM'),'MON-YYYY') AS Year_of_Hiring,
COUNT(empno) No_of_Joinees
FROM emp
GROUP BY TRUNC(hiredate, 'MM')
ORDER BY TRUNC(hiredate, 'MM');

SQL select query returning wrong order by DESC

This is my query which is not returning the correct result ordered by RegistrationDate Desc:
SELECT
Team,
CONVERT(VARCHAR(10), RegistrationDate, 103) AS RegistrationDate,
FormFilledAt, CreationBy
FROM
Table_Candidate_Info
WHERE
Status = 'Completed'
GROUP BY
Team, CONVERT(VARCHAR(10), RegistrationDate, 103), FormFilledAt, CreationBy
ORDER BY
RegistrationDate DESC
If I will use this query, it's returning the correct order by RegistrationDate Desc
select *
from Table_Candidate_Info
order by RegistrationDate desc
I want above first query should be RegistrationDate order by Desc with group by query
Try
order by CONVERT(VARCHAR(10),RegistrationDate,103) desc
or better if you want really keep order by date (and not text) try this:
select Team, CONVERT(VARCHAR(10),RegistrationDate,103) as RegistrationDate, FormFilledAt,CreationBy
from (
Select Team, cast(RegistrationDate as date) as RegistrationDate ,FormFilledAt,CreationBy
from Table_Candidate_Info
where Status='Completed'
group by Team,cast(RegistrationDate as date) ,FormFilledAt,CreationBy
) tmp
order by RegistrationDate desc
Note: if you want group by date + time remove cast… as date
use distinct and CONVERT(VARCHAR(10),RegistrationDate,103) in order by clause
Select distinct Team,CONVERT(VARCHAR(10),RegistrationDate,103)as RegistrationDate ,FormFilledAt,CreationBy
from Table_Candidate_Info where Status='Completed'
order by CONVERT(VARCHAR(10),RegistrationDate,103) desc
Note: You don't need group by since you are not using any aggregated function
The reason why results are not ordered by RegistrationDate when you convert it to a varchar in Select clause is because Order By clause is logically processed after evaluation of Select clause.
Now in first query when you write
Select * from Table_Candidate_Info order by RegistrationDate desc
[Though writing * in select list is a very bad practice] format of RegistrationDate still remains date in Select clause which holds true for further logical processing phase of Order By clause. Hence 31.01.2019 comes first and 31.12.2018 later.
But when you convert it to varchar(10) to get a required format then actually Order By clause is ordering a Varchar and not Date. Hence 31/12/2018 comes first and 31/01/2019 comes after it.
To resolve the problem if you want to retain the formatting of datetime/date column in Select but Order By with Date value then simply cast the datetime column back to Date in Order by clause.
Pseudo code as:
select CONVERT(VARCHAR(10),RegistrationDate,103) as RegistrationDate from
Table_Candidate_Info
order by cast(RegistrationDate as Date) desc -- cast it back to date
Demo Link here: https://rextester.com/WMLQL78387

Date in right format

guys. I hava the query,which counts the number of some events per one day.
But it returns date in wrong format.
select trunc(action_dt) as action_dt, count(*) as cnt
from stat.jurnal_orders
where action_dt between TO_DATE('17.05.12','DD/MM/YY') AND TO_DATE('12.11.13','DD/MM/YY')
group by trunc(action_dt)
order by action_dt asc
In database I have my date in DD.MM.YYYY but I want YYYY/MM/DD
Can somebody help me with that query?
you have two options
First - explicitly set the format you want in the query using TO_CHAR
select to_char(trunc(action_dt),'yyyy/mm/dd') as action_dt, count(*) as cnt
from stat.jurnal_orders
where action_dt between TO_DATE('17.05.12','DD/MM/YY') AND TO_DATE('12.11.13','DD/MM/YY')
group by to_char(trunc(action_dt),'yyyy/mm/dd')
order by action_dt asc
Second, set the nls_date_format at session level.
alter session set nls_date_format = 'yyyy/mm/dd';
and you query
select trunc(action_dt) as action_dt, count(*) as cnt
from stat.jurnal_orders
where action_dt between TO_DATE('2012/05/17') AND TO_DATE('2013/12/11')
group by trunc(action_dt)
order by action_dt asc
To convert dates into a different format you can use the Oracle TO_CHAR function. http://www.techonthenet.com/oracle/functions/to_char.php
For your example, assuming you want to TRUNC the date first, you can use it like so:
SELECT TO_CHAR(TRUNC(action_dt), 'YYYY/MM/DD') as action_dt
FROM some_table
Please try TO_CHAR:
select TO_CHAR (sysdate, 'YYYY/MM/DD') from dual;
SELECT REPLACE(CONVERT(VARCHAR(10), action_dt, 102), '.', '/')
http://msdn.microsoft.com/en-us/library/ms187928.aspx
EDIT: This is for T-SQL not Oracle. Misread the question.

Group by a generated column

I'm trying to group data by minutes, so I tried this query:
SELECT FROM_UNIXTIME(
unix_timestamp (time, 'yyyy-mm-dd hh:mm:ss'), 'yyyy-mm-dd hh:mm') as ts,
count (*) as cnt
from toucher group by ts limit 10;
Then hive tells me no such column,
FAILED: SemanticException [Error 10004]: Line 1:134 Invalid table
alias or column reference 'ts': (possible column names are: time, ip,
username, code)
So is it not supported by hive?
SELECT FROM_UNIXTIME(unix_timestamp (time, 'yyyy-mm-dd hh:mm:ss'), 'yyyy-mm-dd hh:mm') as ts,
count (*) as cnt
from toucher
group by FROM_UNIXTIME(unix_timestamp (time, 'yyyy-mm-dd hh:mm:ss'), 'yyyy-mm-dd hh:mm') limit 10;
or and better
select t.ts, count(*) from
(SELECT FROM_UNIXTIME(unix_timestamp (time, 'yyyy-mm-dd hh:mm:ss'), 'yyyy-mm-dd hh:mm') as ts
from toucher ) t
group by t.ts limit 10;
As is the case with most relational database systems, the SELECT clause is processed after the GROUP BY clause. This means you cannot use columns aliased in the SELECT (such as ts in this example) in your GROUP BY.
There are essentially two ways around this. Both are correct, but some people have preference for one over the other for various reasons.
First, you could group by the original expression, rather than the alias. This results in duplicate code, as you will have the exact same expression in both your SELECT and GROUP BY clause.
SELECT
FROM_UNIXTIME(unix_timestamp(time,'yyyy-mm-dd hh:mm:ss'),'yyyy-mm-dd hh:mm') as ts,
COUNT(*) as cnt
FROM toucher
GROUP BY FROM_UNIXTIME(unix_timestamp(time,'yyyy-mm-dd hh:mm:ss'),'yyyy-mm-dd hh:mm')
LIMIT 10;
A second approach is to wrap your expression and alias in a subquery. This means you do not have to duplicate your expression, but you will have two nested queries and this may have performance implications.
SELECT
ts,
COUNT(*) as cnt
FROM
(SELECT
FROM_UNIXTIME(unix_timestamp(time,'yyyy-mm-dd hh:mm:ss'),'yyyy-mm-dd hh:mm') as ts,
FROM toucher) x
GROUP BY x.ts
LIMIT 10;
Both should have the same result. Which you should use in this case will depend on your particular use; or perhaps personal preference.
Hope that helps.