Case having subquery for Oracle bot working - sql

I am facing some problem in CASE query in Oracle
select
case
when substr(object_subtype,0,1) = '8'
then
'Planatias'
when substr(object_subtype,0,1) = '1'
then
'Licence'
when substr(object_subtype,0,1) = '4'
then
'PMA'
when substr(object_subtype,0,1) = '7'
then
'Location'
else
'no'
end objectType,
id ,substr(object_subtype,0,1)
from amatia_logtask order by 1
Now my problem is I have 4 different tables for each number from case
select * from amatia_licencias ;
select * from amatia_locacion ;
select * from amatia_pma;
select id_plantilla from amatia_plantillas;
And I want specific field from these 4 table with respect to their Id in CASE statment
but query like this
select
case
when substr(object_subtype,0,1) = '8'
then
select id_pma from amatia_plantillas where id_plantilla = substr(object_subtype,3)
when substr(object_subtype,0,1) = '1'
then
'Licence'
when substr(object_subtype,0,1) = '4'
then
'PMA'
when substr(object_subtype,0,1) = '7'
then
'Location'
else
'no'
end objectType,
id ,substr(object_subtype,0,1)
from amatia_logtask order by 1
is not working for me
giving This error
ORA-00936: missing expression
00936. 00000 - "missing expression"
*Cause:
*Action:
Error at Line: 5 Column: 15

CASE statements return expressions: SELECT statements don't count as expressions in this context. So don't use CASE here, use outer joins.
You haven't provided enough details for us to guarantee working SQL so you'll have to pick the bones out of this:
with logtask as ( select id
, substr(object_subtype,0,1) as st_1
, substr(object_subtype,3) as st_3
from amatia_logtask
)
select logtask.id
, logtask.st_1
, coalesce ( apla.id_pma
, alic.id_blah
, aloc.id_meh
, apma.id_etc
, 'no' ) as whatever
from logtask
left join amatia_plantillas pla
on logtask.st_1 = apla.id_plantilla
left join amatia_licencias alic
on logtask.st_1 = alic.id_licencia
left join amatia_locacion aloc
on logtask.st_1 = aloc.id_locacion
left join amatia_pma apma
on logtask.st_1 = apma.id_pma
order by 3, 1
/

It is possible to use subqueries - BUT they MUST only have one row and one column. Think about the result of a query in columns/rows :
| COL1 | COL2 |
|------|------|
| a | x |
| b | y |
each "cell" holds one value (and one value only)
| COL1 | COL2 |
|------|----------------------------------------------------------------------|
| a | cannot be a "select *" subquery because that is more than one column |
| b | y |
So, IF you use subqueries in a select clause, they can only return one value (one row, one column) so the subquery must be carefully written
CREATE TABLE A_TABLE
("COL1" varchar2(1), "COL2" varchar2(1))
;
INSERT ALL
INTO A_TABLE ("COL1", "COL2")
VALUES ('a', 'x')
INTO A_TABLE ("COL1", "COL2")
VALUES ('b', 'y')
SELECT * FROM dual
;
**Query 1**:
select
case
when col1 = 'a' then (select 'subquery 1' from dual)
when col1 = 'b' then (select 'subquery 2' from dual)
else (select 'one value' from dual)
end as col1_case
from a_table
**[Results][2]**:
| COL1_CASE |
|------------|
| subquery 1 |
| subquery 2 |
http://sqlfiddle.com/#!4/76041/3
I'm NOT recommending it, I'm merely showing the method. I would use joins in preference if it is feasible.

Related

how to avoid duplicates in hive query

I have two tables:
table1
the_date | my_id |
02/03/2021,123
02/03/2021, 1234
02/03/2021, 12345
table2
the_date | my_id |seq | txt
02/03/2021, 1234, 1 , 'OK'
02/03/2021, 12345, 1, 'OK'
02/03/2021, 12345, 2, 'HELLO HI THERE'
02/03/2021, 123456, 1, 'Ok'
Here is my code:
WITH AB AS (
SELECT A1.my_id
FROM DB1.table1 A1 , DB1.MSG_REC A2 WHERE
A1.my_id=A2.my_id
),
BC AS (
SELECT AB.the_date
COUNT ( DISTINCT (CASE WHEN (TXT like '%OK%') THEN AB.my_id ELSE NULL END )) AS
CASE1 ,
COUNT ( DISTINCT (CASE WHEN (TXT like '%HELLO HI THERE%') THEN AB.my_id ELSE NULL END )) AS
CASE2
FROM AB left JOIN DB1.my_id BC ON AB.my_id =BC.my_id
The issue that stems from above is I am looping over the value '12345' twice because it satisfies both of the case statements.
That causes data duplicates when capturing metrics of the counts. Is there a way to execute the first case and then perform the second case but exclude looping any of the "my_id' records from the first case.
So for example, when it is time to run the above script and the first case executes, it will pick up the below records and the count would be 3
02/03/2021, 1234, 1 , 'OK'
02/03/2021, 12345, 1, 'OK'
02/03/2021, 123456, 1, 'Ok
The second case should only be looping through the below records and the count would be only 1
02/03/2021, 12345, 2, 'HELLO HI THERE'
CASE1 would be 4 and CASE2 would by 2 if I don't create a condition to circumvent this issue. Any tips or suggestions?
Assign case to each your ID before DISTINCT aggregation . After that do distinct aggregation, in such way you will eliminate same IDs counted in different cases. See comments in the code:
select --do final distinct aggregation
count(distinct (case when assigned_case='CASE1' then my_id else null end ) ) as CASE1,
count(distinct (case when assigned_case='CASE2' then my_id else null end ) ) as CASE2
from
(
select my_id
--assign single CASE to all rows with the same id based on some logic:
case when case1_flag = 1 then 'CASE1'
when case1_flag = 1 then 'CASE2'
else NULL
end as assigned_case
from
(--calculate all CASE flags for each ID
select AB.my_id,
max(CASE WHEN (TXT like '%OK%') THEN 1 ELSE NULL END) over (partition by AB.my_id) as case1_flag
max(CASE WHEN (TXT like '%HELLO HI THERE%') THEN 1 ELSE NULL END) over (partition by AB.my_id) as case2_flag
from ...
) s
) s

How can I acces the output from the first select statement

I have a table Like this
Col1 | Col2
-----------
a | d
b | e
c | a
Now I want to create an statement to get an output like this:
First| Second
-------------------
a | Amsterdamm
b | Berlin
c | Canada
...
So far I have this consturct what is not working
SELECT *
FROM(
SELECT DISTINCT
CASE
when Col1 IS NULL then 'NA'
else Col1
END
FROM Table1
UNION
SELECT DISTINCT
CASE
when Col2 IS NULL then 'NA'
else Col2
END
FROM Table1
) AS First
,
(
SELECT DISTINCT
when First= 'a' then 'Amsterdam'
when First= 'b' then 'Berlin'
when First= 'c' then 'Canada'
) AS Second
;
can you help me with that
Sorry I have to edit my question to be more specific.
Not as familiar with DB2... I'll lookup if it has a concat function in a sec... and it does.
SELECT First, case when first = 'a' then
concat('This is a ',first)
case when first = 'b' then
concat('To Be or not to ',first)
case else
concat('This is a ',first) end as Second
FROM (
SELECT coalesce(col1, 'NA') as First
FROM Table
UNION
SELECT coalesce(col2, 'NA')
FROM table) SRC
WHERE first <> 'NA'
What this does is generate a single inline view called src with a column called first. If col1 or col2 of table are null then it substitutes NA for that value. It then concatenates first and the desired text excluding records with a first value of 'NA'
Or if you just create an inline table with the desired values and join in...
SELECT First, x.b as Second
FROM (
SELECT coalesce(col1, 'NA') as First
FROM Table
UNION
SELECT coalesce(col2, 'NA')
FROM table) SRC
INNER JOIN (select a,b
from (values ('a', 'This is a'),
('b', 'To B or not to' ),
('c', 'I like cat whose name starts with')) as x(a,b)) X;
on X.a = src.first
WHERE first <> 'NA'
Personally I find the 2nd option easier to read. Though if you have meaning for a,b,c I would think you'd want that stored in a table somewhere for additional access. In code seems like a bad place to store data like this that could change.
Assuming you want
a this is a a
b this is a b
c this is a c
d this is a d
e this is a e
thanks to xQbert
I could solve this problem like this
SELECT FirstRow, concat
(
CASE FirstRow
WHEN 'AN' then 'amerstdam'
WHEN 'G' then 'berlin'
ELSE 'NA'
END, ''
) AS SecondRow
FROM(
Select coalesce (Col1, 'NA') as FirstRow
FROM Table1
UNION
Select coalesce (Col2, 'NA')
FROM Table1) SRC
WHERE FirstRow <> 'NA'
;

SQL : To get one of the duplicates by using a case statement

I have a table in which there are two columns with duplicates.
id name classname description
-----------------------------
1 a aa aa:abcd
2 a Unknown Unknown
3 b bb unknown
4 c cc abcd
Now I have a select query where in I have to filter out all the duplicates and my description is shown as identifier, my result should be like this,
id name identifier
-----------------
1 a aa
2 b NULL
3 c NULL
where all the description having either without ':' as its char index should display as NULL or Unknown as Null.
I'm using the below select query to filter the duplicates in the 'name' column , but I'm unable to use the same query for description as I'm using case for obtaining result in order to trim my description 'aa: abcd' to aa
select distinct
id,
(select top 1 name
from table1 t
where t.name = t1.name
order by case t1.classname
when 'Unknown Tag Class' then 0
else 1
end
) name,
(case when charindex(':',Description)> 0
then substring(Description,1,(charindex(':',Description)-1))
end
) as Identifier
from table1 t1
In the above query I want to modify the case statement of description so that i can filter duplicates and also trim the values like "aa:abcd" to "aa" and put them in identifier column.
Need help on this.
this is the query i am using
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[EXEC_REP_TransposedTagAttributes]')
AND type in (N'U'))
BEGIN
select distinct
[Att : 42674] as TagID
,Tagname
,isnull([Att : 14591],'-') as OriginatingContractor
,isnull([Att : 14594],'-') as System
,(case when charindex(':',TargetName)> 0 then
substring(TargetName,(charindex(':',TargetName)+1),len(TargetName))
end) as SystemDescription
,(case when charindex(':',TagClassDescription)> 0 then
substring(TagClassDescription,1,(charindex(':',TagClassDescription)-1))
end) as TagIdentifier
from EXEC_REP_TransposedTagAttributes t1
LEFT JOIN (SELECT SourceName, TargetName FROM EXEC_REP_Associations WHERE AssociationType = '3' and TargetClassName = 'SUB SYSTEM') b ON TagName = b.SourceName
where tagname='ZIH-210053' Order by [Att : 42674]
END
ELSE
select 'Reporting Database is being refreshed, please wait.' as errMsg
and the result i am geting is
TagID Tagname OriginatingContractor System SystemDescription TagIdentifier
2609005 ZIH-210053 Hyundai Heavy Industries (Topsides) 210 Slugcatcher NULL
2609005 ZIH-210053 Hyundai Heavy Industries (Topsides) 210 Slugcatcher ZIH
there are also rows which have tag identifier as null and donot have duplicates
select id,name,
CASE WHEN charindex(':',description)>0
THEN LEFT(description,charindex(':',description)-1)
ELSE NULL
END as identifier
from t as t1
where description like '%:%'
or NOT EXISTS (select * from t where t.id<>t1.id and t.name=t1.name);
SQLFiddle demo

sql query group

SQL query question
I have a query like
select proposal_id, service_id,account_type
from table1
The result is like this:
proposal_id service_id account_type
1 1001 INTERVAL
1 1002 INTERVAL
2 1003 NON INTERVAL
2 1004 NON INTERVAL
3 1005 NON INTERVAL
3 1006 INTERVAL
I want to write a query: for each proposal_id, if all the service have INTERVAL then get 'INTERVAL', if all NON-INTERVAL get 'NON-INTERVAL', if both, get 'Both'
For the example above, it should return
proposal_id account_type
1 INTERVAL
2 NON-INTERVAL
3 BOTH
Data:
declare #table table (id int, sid int, acc nvarchar(20))
insert #table VALUES (1,1001,'INTERVAL'),(1,1002,'INTERVAL'),(2,1003,'NON INTERVAL'),(2,1004,'NON INTERVAL'),
(3,1005,'NON INTERVAL'),(3,1006,'INTERVAL')
Query:
select x.Id
, CASE counter
WHEN 1 THEN x.Account_Type
ELSE 'BOTH'
END AS Account_Type
from (
select Id, Count(DISTINCT(acc)) AS counter, MAX(acc) As Account_Type
from #table
GROUP BY Id
) x
Results
Id Account_Type
----------- --------------------
1 INTERVAL
2 NON INTERVAL
3 BOTH
SELECT
b.proposal_id
,CASE
WHEN s1.proposal_id IS NOT NULL AND s2.proposal_id IS NOT NULL THEN 'BOTH'
WHEN s1.proposal_id IS NOT NULL THEN 'INTERVAL'
WHEN s2.proposal_id IS NOT NULL THEN 'NON-INTERVAL'
ELSE 'UNKNOWN'
END [account_type]
FROM table1 b
LEFT JOIN(
SELECT proposal_id,account_type FROM table1 WHERE account_type = 'INTERVAL'
) s1
ON b.proposal_id = s1.proposal_id
LEFT JOIN (
SELECT proposal_id,account_type FROM table1 WHERE account_type = 'NON-INTERVAL'
)s2
ON b.proposal_id = s2.proposal_id
You could use count distinct to determinate if it is both then use CASE to determinate what to display
SELECT DISTINCT proposal.proposal_id,
CASE cou
WHEN 1 THEN type ELSE 'Both' END as TYPE
FROM proposal
INNER JOIN (SELECT proposal_id, count(distinct type) cou
FROM proposal GROUP BY proposal_id) inn
ON proposal.id = inn.id
select proposal_id,
case when count(distinct account_type) > 1 then 'BOTH'
else max(account_type)
end
from table1
group by proposal_id
You have the fiddler here.

How do I modify this query without increasing the number of rows returned?

I've got a sub-select in a query that looks something like this:
left outer join
(select distinct ID from OTHER_TABLE) as MYJOIN
on BASE_OBJECT.ID = MYJOIN.ID
It's pretty straightforward. Checks to see if a certain relation exists between the main object being queried for and the object represented by OTHER_TABLE by whether or not MYJOIN.ID is null on the row in question.
But now the requirements have changed a little. There's another row in OTHER_TABLE that can have a value of 1 or 0, and the query needs to know whether a relation exists between the primary for a 1-value, and also if it exists for a 0 value. The obvious solutions is to put:
left outer join
(select distinct ID, TYPE_VALUE from OTHER_TABLE) as MYJOIN
on BASE_OBJECT.ID = MYJOIN.ID
But that would be wrong because if 0-type and 1-type objects both exist for the same ID, it will increase the number of rows returned by the query, which isn't acceptable. So what I need is some sort of subselect that will return 1 row for each distinct ID, with a "1-type exists" column and a "0-type exists" column. And I have no idea how to code that in SQL.
For example, for the following table,
ID | TYPE_VALUE
_________________
1 | 1
3 | 0
3 | 1
4 | 0
I'd like to see a result set like this:
ID | HAS_TYPE_0 | HAS_TYPE_1
______________________________
1 | 0 | 1
3 | 1 | 1
4 | 1 | 0
Anyone know how I could set up a query to do this? Hopefully with a minimum of ugly hacks?
In the general case, you would use EXISTS:
SELECT DISTINCT ID,
CASE WHEN EXISTS (
SELECT * FROM Table1 y
WHERE y.TYPE_VALUE = 0 AND ID = x.ID)
THEN 1
ELSE 0 END AS HAS_TYPE_0,
CASE WHEN EXISTS (
SELECT * FROM Table1 y
WHERE y.TYPE_VALUE = 1 AND ID = x.ID)
THEN 1
ELSE 0 END AS HAS_TYPE_1
FROM Table1 x;
If you have a very large number of elements in the table, this won't perform so great - those nested subselects are often a kiss of death when it comes to performance.
For your specific case, you could also use GROUP BY and MAX() and MIN() to speed things up:
SELECT
ID,
CASE WHEN MIN(TYPE_VALUE) = 0 THEN '1' ELSE 0 END AS HAS_TYPE_0,
CASE WHEN MAX(TYPE_VALUE) = 1 THEN '1' ELSE 0 END AS HAS_TYPE_1
FROM Table1
GROUP BY ID;
Instead of select distinct ID, TYPE_VALUE from OTHER_TABLE
use
select ID,
MAX(CASE WHEN TYPE_VALUE =0 THEN 1 END) as has_type_0,
MAX(CASE WHEN TYPE_VALUE =1 THEN 1 END) as has_type_1
from OTHER_TABLE
GROUP BY ID;
You can do the same using PIVOT opearator...