group by and union in oracle - sql

I would like to union 2 queries but facing an error in oracle.
select count(*) as faultCount,
COMP_IDENTIFIER
from CORDYS_NCB_LOG
where AUDIT_CONTEXT='FAULT'
union
select count(*) as responseCount,
COMP_IDENTIFIER
from CORDYS_NCB_LOG
where AUDIT_CONTEXT='RESPONSE'
group by COMP_IDENTIFIER
order by responseCount;
Two queries run perfectly individually.but when using union,it says ORA-00904: "RESPONSECOUNT": invalid identifier

The error you've run into
In Oracle, it's best to always name each column in each UNION subquery the same way. In your case, the following should work:
select count(*) as theCount,
COMP_IDENTIFIER
from CORDYS_NCB_LOG
where AUDIT_CONTEXT='FAULT'
group by COMP_IDENTIFIER -- don't forget this
union
select count(*) as theCount,
COMP_IDENTIFIER
from CORDYS_NCB_LOG
where AUDIT_CONTEXT='RESPONSE'
group by COMP_IDENTIFIER
order by theCount;
See also:
Curious issue with Oracle UNION and ORDER BY
A good workaround is, of course, to use indexed column references as suggested by a_horse_with_no_name
The query you really wanted
From your comments, however, I suspect you wanted to write an entirely different query, namely:
select count(case AUDIT_CONTEXT when 'FAULT' then 1 end) as faultCount,
count(case AUDIT_CONTEXT when 'RESPONSE' then 1 end) as responseCount,
COMP_IDENTIFIER
from CORDYS_NCB_LOG
where AUDIT_CONTEXT in ('FAULT', 'RESPONSE')
group by COMP_IDENTIFIER
order by responseCount;

The column names of a union are determined by the first query. So your first column is actually named FAULTCOUNT.
But the easiest way to sort the result of a union is to use the column index:
select ...
union
select ...
order by 1;
You most probably also want to use UNION ALL which avoids removing duplicates between the two queries and is faster than a plain UNION

In Union or Union all query column names are determined by the first query column name.
In your query replace "order by responseCount" with "order by faultCount.

Related

Conditional Order By in sql

I have a sample data, which I want to sort. If User is 1,then sort views in descending, otherwise if User is not 1,then sort normally.
I have written below sql,and I am getting required result.
My Question is Why and How it works?
with data as (
select 2 as User, 1 as Views UNION ALL
select 1,3 UNION ALL
select 4,1 UNION ALL
select 1,5 UNION ALL
select 1,6 UNION ALL
select 2,6 UNION ALL
select 7,2 UNION ALL
select 8,3 UNION ALL
select 3,9
)
select ARRAY_AGG(struct(User,Views) order by if(User=1,1,0) desc ,Views desc )
from data
I am confused with if(User=1,1,0), if User=1,then 1.Is this 1,the
column number? If its column number,then ,when User is not equal to
1,then the value will be 0 ,which is not any column.
I was researching on this,and found that,if I write, if(User=1,100,0) desc ,Views desc ,then also I am getting correct result ,mean numbers in that IF() are not columns, otherwise 100 will produce error ,becoz there is no 100th column.
Can Anyone explain me,how its working?
Image 1
Image 2
Can Anyone explain me,how its working?
I think below is the simplest way to explain/show what is happening here
Consider below slightly modified/simplified example - I eliminated aggregation to focus on ordering aspect only
with data as (
select 2 as user, 1 as views union all
select 1,3 union all
select 4,1 union all
select 1,5 union all
select 1,6 union all
select 2,6 union all
select 7,2 union all
select 8,3 union all
select 3,9
)
select *, if(user=1,1,0) sort
from data
order by sort desc, views desc
output of above is
I don't think you have any doubts why above result is as is - it is just straightforward!!
Now - if you use if(user=1,100,0) - you get
Obviously, exactly same output (in terms of ordering) and I still don't think you have any doubts why it is as it is
So, finally to streamline query - users (or at least power users) would use the shortcut - instead of introducing sort column to use in order by - they would move this into order by itself
Hope this is clear now for you!

Using group/order by with union clause in sql query

I have four sql queries which gave me same columns so I am trying to combine them using UNION clause. Below is what I have tried but it gives me an error:
select clientid,
'Test1' as client_name,
client_timestamp,
sum(client_counts) as count,
processIds as contracts
from output_1
group by 1,2,3,5
order by 1
UNION
select clientid,
'Test2' as client_name,
client_timestamp,
sum(client_counts) as count,
'' as contracts
from output_2
group by 1,2,3,5
order by 1
UNION
select clientid,
'Test3' as client_name,
client_timestamp,
sum(kite_count) as count,
process_metric as contracts
from output_3
group by 1,2,3,5
order by 1
UNION
select clientid,
'Test4' as client_name,
execution_client_ts as client_timestamp,
sum(kite_count) as count,
process_data as contracts
from output_4
group by 1,2,3,5
order by 1
Error I get is "Invalid Syntax" around UNION line. Anything wrong I am doing here?
A union query may only have one order by clause.
If you are satisfied with ordering the whole resultset, you can remove all order by clauses and just keep the very last one, at the end of the query. It applies to the entire dataset that union generates.
Note that your UNIONs are equivalent to UNION ALLs - because the client name is different in each member - and should be phrased as such.
If, on the other hand, you want to order reach sub-result, then this is different. Basically you need a flag in each member, that can then be used to identify each group. The client name might be a good pick, so:
order by client_name, client_id

Single Oracle SQL query with CTE produces "SELECT list inconsistent with GROUP BY" error

I've got an Oracle query (unfortunately, I don't know DBMS version) that needs to return only one row of data. Also, it needs to be a single SELECT query, so temporary tables and parameters declarations are not allowed.
First, I'm using a CTE which aggregates values on all columns except the first, which is used as a GROUP BY condition. I need to display all those values in a single row, which works (I'm using 3 CROSS JOINs on filtered CTE, joining three one-row datasets, resulting in also a one-row dataset).
If I run only the CTE (not the whole CTE, just the SELECT in it), it works and produces no error. But if I wrap this SELECT statement in WITH ... AS construct, I'm given the error - Oracle SQL Developer.
Here is the CTE:
WITH
FRUITDATASET AS (
SELECT
-- FROM HERE, ORACLE SQL DEVELOPER MARKS LINES AS ERRONEOUS
FRUITTYPE,
COUNT(LONDONFRESH) AS LONDONFRESH,
COUNT(BERLINFRESH) AS BERLINFRESH,
SUM(0) AS LONDONSTALE,
SUM(0) AS BERLINSTALE
-- FROM HERE, THE QUERY IS VALID AGAIN
FROM
[...]
GROUP BY
FRUITTYPE
UNION ALL
SELECT
-- FROM HERE, THE ERROR HAPPENS AGAIN
FRUITTYPE,
SUM(0) AS LONDONFRESH,
SUM(0) AS BERLINFRESH,
COUNT(LONDONSTALE) AS LONDONSTALE,
COUNT(BERLINSTALE) AS BERLINSTALE
-- FROM HERE IT'S OKAY
FROM
[...]
GROUP BY
FRUITTYPE
)
Here is how I use the CTE:
SELECT
SUM(APPLES.LONDONFRESH) AS LONDONFRESHAPPLES,
SUM(APPLES.BERLINFRESH) AS BERLINFRESHAPPLES,
SUM(APPLES.LONDONSTALE) AS LONDONSTALEAPPLES,
SUM(APPLES.BERLINSTALE) AS BERLINSTALEAPPLES,
SUM(GRAPES.LONDONFRESH) AS LONDONFRESHGRAPES,
SUM(GRAPES.BERLINFRESH) AS BERLINFRESHGRAPES,
SUM(GRAPES.LONDONSTALE) AS LONDONSTALEGRAPES,
SUM(GRAPES.BERLINSTALE) AS BERLINSTALEGRAPES
FROM
DUAL
CROSS JOIN FRUITDATASET APPLES
ON APPLES.FRUITTYPE = 'APPLE'
CROSS JOIN FRUITDATASET GRAPES
ON GRAPES.FRUITTYPE = 'GRAPE'
Query runs anyway when I run it from SQL Developer, but if I put it into a report, it throws an exception. I've tried putting
NULL AS LONDONFRESH
[...]
GROUP BY
FRUITTYPE,
NULL
but it still doesn't work. Can you guys help me find out what's wrong with this query?
EDIT:
I think I probably solved this by using analytic functions:
WITH
FRUITDATASET AS (
SELECT
*
FROM (
SELECT
DISTINCT FRUITTYPE,
COUNT(LONDONFRESH) OVER(PARTITION BY FRUITTYPE) AS LONDONFRESH,
COUNT(BERLINFRESH) OVER(PARTITION BY FRUITTYPE) AS BERLINFRESH,
SUM(NULL) OVER(PARTITION BY FRUITTYPE) AS LONDONSTALE,
SUM(NULL) OVER(PARTITION BY FRUITTYPE) AS BERLINSTALE
FROM
[...]
)
UNION ALL
SELECT
*
FROM (
SELECT
DISTINCT FRUITTYPE,
SUM(NULL) OVER(PARTITION BY FRUITTYPE) AS LONDONFRESH,
SUM(NULL) OVER(PARTITION BY FRUITTYPE) AS BERLINFRESH,
COUNT(LONDONSTALE) OVER(PARTITION BY FRUITTYPE) AS LONDONSTALE,
COUNT(BERLINSTALE) OVER(PARTITION BY FRUITTYPE) AS BERLINSTALE
FROM
[...]
)
)
Right now I'm unable to check this solution on the server, but I'll post an answer as soon as I find out.
Apparently wrapping CTE into SELECT * FROM does the trick. Everything is working now.

How to do union all with different order by conditions

I have a table with data like
I want all the records from the table but which the record having EnquiryStatus=1 and order by LastAttendendedDate should come on the top and remaining records should come after those records. I tried to select twice with where condition and tried to union all them, But with that union all not allowing me to order by on different ways. I can do it in c# by retriving the data as two table and merge them as single. But I want it in sql..
EDITS:
I want something like
Select * From EnquiryMaster A Where A.BranchID=16 and EnquiryStatus=1 ORDER BY A.CreatedDate Desc
UNION ALL
Select * From EnquiryMaster A Where A.BranchID=16 and EnquiryStatus in(0,2,3) ORDER BY EnquiryStatus,A.CreatedDate Desc
SELECT * FROM TABLE_NAME WHERE ORDER BY CASE WHEN EnquiryStatus='1' THEN LastAttendendedDate END DESC
You can use this in sql.
Try this
select * from your_table
order by case when EnquiryStatus=1 then LastAttendendedDate end DESC

How to do a query that is agnostic of the sort field?

I have multiple tables that have the same date_time added field in each table. After doing a UNION of all tables i want to sort them by the most recent one. But the query will tell me that the i have to add a table name like videos.date_time rather than ORDER BY date_time. How can i structure the query so that it is agnostic of the which date_time field?
Unless you are using a proprietary feature such as SQL Server's TOP directive, the Order By in a Union query is always at the bottom and always applies to the entire query. E.g.
Select Col1, date_time
From Table1
Union All
Select Col1, date_time
From Table2
Order By date_time
If your query does include various elements such TOP or LIMIT which require an Order By and thus you want to differentiate the Order By's, then you can encapsulate your query into a derived table:
Select Col, date_time
From (
Select Col1 As Col, date_time
From Table1
Union All
Select Col1, date_time
From Table2
) As Z
Order By Z.date_time
In SQL Server you can also order by a column number, e.g. "ORDER BY 2" in which case whatever the second column is in your union set would be the sort target.
As I understand you have X tables (where X is > 1), and every table have it's own date_time column and you want to get last updated. If that's true, than one of the possible ways is to do it that way
SELECT id, date_added FROM table1
UNION ALL
SELECT id, date_added FROM table2
ORDER BY date_added DESC;
Other ways which I have in mind is when you fetch results, put them in array and do the "magic" inside it.