Error in my Subquery Factoring (WITH) Clause - oracle

I have an error when I run this script :
WITH q AS (
SELECT COUNT(id)
FROM test
)
SELECT 1,
CASE
WHEN q=0 then 'toto'
ELSE 'titi'
END
FROM dual;
I must to use a Subquery Factoring (WITH) clause.
The idea is to display 'toto' when the count equal 0 else I must display 'titi'.

Use an alias for the result, and FROM q
WITH q AS (
SELECT COUNT(id) as total
FROM test
)
SELECT 1,
CASE
WHEN q.total = 0 THEN 'toto'
ELSE 'titi'
END
FROM q;

You can simplify it to:
SELECT 1,
CASE COUNT(*) WHEN 0 then 'toto' ELSE 'titi' END
FROM test;
The error in your query is that you have created a named subquery q but then you are selecting the column q from the DUAL table (which does not have a column q).
You can fix your query like this:
WITH q AS (
SELECT COUNT(id) AS cnt -- name this column
FROM test
)
SELECT 1,
CASE WHEN cnt = 0 -- use the column you named previously
THEN 'toto'
ELSE 'titi'
END
FROM q; -- use the named subquery q not the dual table

Related

Subquery as CASE WHEN condition

Below query, syntax error happens on AS PQ_COUNT
SELECT CASE WHEN
RESULTS LIKE '%PQ - Duplicate%' AND
(SELECT COUNT(*) FROM MY_TABLE WHERE ID = '998877'AND FINAL_RESULTS='FL_57') AS PQ_COUNT >= 1
THEN 'PQ count = '|| PQ_COUNT
ELSE RESULTS END AS RESULTS
If I moved AS PQ_COUNT inside select query,
(SELECT COUNT(*) AS PQ_COUNT FROM MY_TABLE WHERE ID = '998877'AND FINAL_RESULTS='FL_57') >= 1
the reference of PQ_COUNT in THEN block become invalid identifier (ORA-00904)
What might go wrong here when addressing subquery as CASE WHEN condition?
One option is to use a subquery (or a CTE, as in my example) to calculate number of rows that satisfy condition, and then - as it contains only one row - cross join it to my_table. Something like this:
SQL> WITH
2 my_table (id, final_results, results) AS
3 -- sample data
4 (SELECT '998877', 'FL_57', 'PQ - Duplicate' FROM DUAL),
5 cnt AS
6 -- calculate COUNT first ...
7 (SELECT COUNT (*) pq_count --> pq_count
8 FROM MY_TABLE
9 WHERE ID = '998877'
10 AND FINAL_RESULTS = 'FL_57')
11 -- ... then re-use it in "main" query
12 SELECT CASE
13 WHEN a.results LIKE '%PQ - Duplicate%'
14 AND b.pq_count >= 1 --> reused here
15 THEN
16 'PQ count = ' || b.PQ_COUNT --> and here
17 ELSE
18 a.results
19 END AS results
20 FROM my_table a CROSS JOIN cnt b;
RESULTS
---------------------------------------------------
PQ count = 1
SQL>
You cannot refer to an alias in the same sub-query where you create it; you need to nest sub-queries (or use a sub-query factoring clause; also called a CTE or WITH clause) and refer to it in the outer one:
SELECT CASE
WHEN results LIKE '%PQ - Duplicate%'
AND pq_count >= 1
THEN 'PQ count = '|| pq_count
ELSE results
END AS RESULTS
FROM (
SELECT results,
( SELECT COUNT(*)
FROM MY_TABLE
WHERE ID = '998877'
AND FINAL_RESULTS='FL_57'
) AS pq_count
FROM your_table
);

how to enter a date subquery in oracle

Hello I would like to add an additional column called (DATE), but that does not affect the previously selected data as I could add that column ... (DATE IS IN VARIABLE_VALORES_SMEC), try to do a subquery in the select but it sends me this error: single- row subquery returns more than one row
Select Max(A1.VALOR) AS VALOR ,
(SELECT FECHA AS FC FROM VARIABLE_VALORES_SMEC WHERE ID_AGENTE IN A1.ID_AGENTE <--here is the problem
) MES,
(SELECT CODIGO_AGENTE FROM AGENTES WHERE ID_AGENTE = A1.ID_AGENTE
) Agentess,
(SELECT NOMBRE_AGENTE FROM AGENTES WHERE ID_AGENTE = A1.ID_AGENTE
) Nombre_Agente
FROM VARIABLE_VALORES_SMEC A1
WHERE A1.VALOR < '1'
AND A1.VALOR != '0'
AND A1.ID_AGENTE IN (SELECT C1.ID_AGENTE FROM VARIABLE_VALORES_SMEC C1
WHERE A1.FECHA = C1.FECHA)
AND A1.ID_AGENTE IN (SELECT B1.ID_AGENTE
FROM AGENTES B1
WHERE ID_CATEGORIA_AGENTE = 'AC006'
)
AND (A1.FECHA between (ADD_MONTHS(TO_DATE(:FECHAIN,'MM/DD/YYYY'),-1)) AND (LAST_DAY(ADD_MONTHS(TO_DATE(:FECHAIN, 'MM/DD/YYYY'),-1))))
AND A1.ID_VARIABLE LIKE '%_calc_total_pot#%'
GROUP BY ID_AGENTE
single- row subquery returns more than one row
This error means that your subquery returns more than 1 row (replace FECHA with count(*) and you will see how many rows does it return), so you need:
aggregate returned values, for example using listagg() function, ie:
(select listagg(FECHA)within group(order by 1) from ...
or
2. analyze your predicates in the subquery so that returns just 1 row.
PS. To make your queries more clear and readable, it would be better to use aliases for all tables and columns, for example
(SELECT sq1.FECHA AS FC FROM VARIABLE_VALORES_SMEC sq1 WHERE sq1.ID_AGENTE IN A1.ID_AGENTE) MES,
PS2. Don't use IN for single value, just use "="
Your column FECHA is from table VARIABLE_VALORES_SMEC on which your main query is executing, then why don't you simply use direct column instead of subquery as follows:
Select Max(A1.VALOR) AS VALOR ,
Max(FECHA) keep (dense_rank last order by value) AS MES
.....
.....

Oracle filter results by limit

I am new to Oracle and was hoping someone could help me.
I have this stored procedure:
procedure ListCatalogues(P_CUR out sys_refcursor,
P_CATALOGUENAME varchar2 default '%',
P_LIMIT number,
P_MEMBERS number default -1) is
begin
open P_CUR for
select *
from ( select h.catalogueid id,
h.cataloguename name,
case
when h.uniquecatalogue = 'N'
then 1
else 0
end includeproducts,
case
when h.active = 'Y'
then 1
else 0
end active,
case
when h.ownbrandedlabels = 'Y'
then 1
else 0
end ownlabels,
( select count(*)
from cc_custprofiles t
where t.catalogueid = h.catalogueid
) members
from cc_ob_catalogueheader h
where upper(h.cataloguename) like upper('%'||P_CATALOGUENAME||'%')
and (select count(*) from cc_custprofiles t where t.catalogueid = h.catalogueid) >= P_MEMBERS
order by h.catalogueid
)
where rownum <= P_LIMIT;
end ListCatalogues;
As you can see, it accepts a P_LIMIT parameter which allows for limiting the results returned. This is fine, but I want to expand on it a little.
If the limit is 10, then return 10 rows, but if the limit is 0, return everything. Can someone help me change the query to match my criteria?
I managed this after a bit of looking around:
where rownum <= case when P_LIMIT = 0 then rownum else P_LIMIT end;

Select data depend with IF ELSE condition

I have a query as below :
SELECT R.*
FROM
(
WITH TABLE_X AS
(
SELECT A,B,C FROM Y
)
--PSEUDO CODE
IF (COUNT(TABLE_X.*) > 0)
THEN SELECT CONCAT(A ,B, C) FROM TABLE_X
ELSE 'No Data'
END
) R
In this case, If TABLE_X have data, the selection will return A,B,C. In others way, this will return something else like 'No data'.
Please help me clarify and suggest some soluiton on it.
Thank you for your attention.
If there is at most one row in TABLE_X, then you can use aggregation:
WITH TABLE_X AS (
SELECT A, B, C FROM Y
)
SELECT (CASE WHEN COUNT(*) = 0 THEN 'No Data'
ELSE MAX(A || B || C)
END) as col
FROM TABLE_X;
Alternatively, use UNION ALL:
WITH TABLE_X AS (
SELECT A, B, C FROM Y
)
SELECT A || B || C as col
FROM TABLE_X
UNION ALL
SELECT 'No Data'
FROM Dual
WHERE NOT EXISTS (SELECT 1 FROM TABLE_X);
Looking too you query i think you simply need
select nvl( A||B,||C , 'No data')
from y

t-sql TVF function slow when using localvariables in "CASE statement"

I have sql like below inside a Multi-Step Table valued function..I have shortened the query a bit to make it easy to understand.
CREATE FUNCTION [dbo].[fn_ph]
(
-- Add the parameters for the function here
#pAsOfDate date,
#pAccountId nvarchar(15)
)
RETURNS #HH TABLE
(
-- Add the column definitions for the TABLE variable here
AsOfDate date,
AccountId nvarchar(15),
LongName varchar(100),
ShortName varchar(100)
)
AS
BEGIN
declare #longOrShortIndicator int
select #longOrShortIndicator = COUNT(distinct LongOrShortIndicator) from table1 a
select a.*,
case
when a.SecType='CASH' and #longOrShortIndicator > 1 then 'C'
else a.LongOrShortIndicator
end as LongOrShortIndicator
from Table1 a
END
The expression when a.SecType='CASH' and #longOrShortIndicator > 1 then 'C' is the bottleneck.
if i remove the #longOrShortIndicator > 1 the query runs fast
If i run the query outside of the function it returns fast...
Why is the local variable slowing down the entire query? Any help would be appreciated.
thanks
The listing does not show what you want to do with #HH, your return table, but in #longOrShortIndicator you are obviously counting rows in table1. If you're doing it many times, e.g. for all rows of your return table, then it is slow indeed, it would be slow even on the death star.
Guessing here: maybe you could try moving the #LongOrShortIndicator variable out of the query and into an IF statement:
declare #longOrShortIndicator int
select #longOrShortIndicator = COUNT(distinct LongOrShortIndicator) from table1 a
IF #longOrShortIndicator > 1 BEGIN
select a.*,
CASE when a.SecType='CASH' then 'C'
else a.LongOrShortIndicator
end as LongOrShortIndicator
from Table1 a
END ELSE BEGIN
select a.*, a.LongOrShortIndicator
from Table1 a
END

Resources